题目大意: 有k个好人跟k个坏人按顺序坐着,然后按第m个杀人,求出把坏人全部先杀光的m的最小值。   0<k<14。典型的约瑟环问题。 解题思路: 一开始看见数据量那么小,还以为暴力一定可以出来,结果,好吧,当k为0以上时,时间大得惊人,自己暴力的方法还是有很大问题啊。 比较标准的做法是:在这么多个人中,始终用start跟end来确定好人那个序列的位置。 比如一开始是1 2 3 4 5 6,那么start = 0,end = 3(从0开始计数)当m等于5的时候,kill后就剩下1 2 3 4 6 ,重新拍下序列变成 6 1 2 3 4 ,这时候 start = ((start-m)%n+n)%n; end =  ((end-m)%n+n)%n; n是当前剩下的人数。定完位置之后,kill的位置为kill = (m-1)%n; 这样就可以做了。 AC代码:
#include
using namespace std;

bool joseph(int k, int m)
{
    int start = 0, end = k - 1; //定位,定好人的位置
    int kill;//杀人的序号
    for(int n = 2 * k; n > k; n--) //n代表人数
    {
        kill = (m - 1) % n;
        if(kill >= start && kill <= end)
        {
            return false;
        }
        start = ((start - m) % n + n) % n;//定位,加n模n是为了防止负数
        end = ((end - m) % n + n) % n;
    }
    return true;
}

int main(void)
{
    int f[14];
    for(int i = 1; i < 14; i++)
        for(int j = 1; ; j++)
        {
            if(joseph(i, j))
            {
                f[i] = j;
                break;
            }
        }
    int k;
    while(scanf("%d", &k), k)
    {
        printf("%d\n", f[k]);
    }
    return 0;
}
TLE代码:
#include
using namespace std;
const int MAX = 30;
const int M = 100005;
int main(void)
{

    int pe[MAX];
    for(int k = 11; k < 14; k++)
    {
        bool mark[MAX];

        for(int i = 0; i <= k; i++)
            pe[i] = 1;
        for(int i = k + 1; i <= 2 * k; i++)
            pe[i] = 2;//bad guys
        int min = 0;//结果
        bool flag = false;
        for(int m = 1; ; m++)
        {
            int count = 0, index = 1;
            int bad = k;//坏人
            //int m = 30;
            memset(mark, false, sizeof(mark));

            while(1)
            {
                if(mark[index] == true)
                {
                    if(index == 2 * k) //指向的移动
                    {
                        index = 1;
                    }
                    else
                        index++;
                    continue;
                }

                count++;
                if(count == m)
                {
                    if(pe[index] == 1)//杀了好人
                        break;
                    else
                    {
                        mark[index] = true;
                        bad--;
                        if(bad == 0)
                        {
                            min = m;
                            flag = true;
                            break;
                        }
                    }
                    count = 0;//重新计数
                }

                if(index == 2 * k) //指向的移动
                {
                    index = 1;
                }
                else
                    index++;
            }

            if(flag)
                break;
        }
        //for(int i = 1; i <= 2*k; i++)
        //	printf("%d ", mark[i]);
        //printf("\n");
        printf("%d\n", min);
    }
    return 0;
}
posted on 2012-02-14 00:26  cchun  阅读(765)  评论(0编辑  收藏  举报