TOJ1007

http://acm.tju.edu.cn/toj/showp1007.html

这个题好像是一个约瑟夫环变形的题,乍一看没什么思路,后来在网上参考解题方法,找到了一个比较不错的思路。

大体思路是,规定好人坏人各k个,那么假设总人数就是2*k,用j指向将要杀死的那个人,从0开始代表第一个人,因为先要杀死全部的坏人,所以m一定是大于k,从k+1开始。注意下面这个式子:

j = (j+m-1)%sum;

这个式子是计算j的公式,j+m-1代表指向的第几个人(从0开始所以减一),再对sum取余。同时sum--,表示杀死了一个人。如果好人被杀死,那么说明这个m不符合要求,退出内层循环,m++;如果只剩下了好人,代表坏人都被杀死了,符合要求,同样退出内层循环,返回m值即可。

值得注意的是,当我直接返回m时,提交之后报错(Time Limit Exceed),后来我改成用数组存储每一个k对应的m值,成功AC。在网上查了一下,发现这种方法叫做“打表”,大概就是把所有可能的结果都存储在一个数组中,用的时候直接取出来。这种方法适用于数据范围小但是计算量大的情况,对应于这道题则刚好适用。

代码:

#include <stdio.h>
#include <stdlib.h>

int result[15];

int Joseph(int k){
    int sum;
    int m, flag;
    if(result[k])   return result[k];
    for(m = k+1; ;m++){
        sum = 2*k;
        int j = 0;      //当前指向的人,0代表第一个
        while(1){
            j = (j+m-1)%sum;
            sum--;      //人数少一个
            if(j < k){  //代表杀死好人的情况
                flag = 0;
                break;
            }
            if(sum == k){   //代表只剩下好人
                flag = 1;
                break;
            }
        }
        if(flag){
            result[k] = m;
            return result[k];
        }
    }
}

int main(){
    int k;
    while(scanf("%d", &k) && k != 0){
        printf("%d\n", Joseph(k));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/rr572078051/article/details/82944215
今日推荐