标签:
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 52097 | Accepted: 19838 |
Description
Input
Output
Sample Input
3 4 0
Sample Output
5 30
Source
大致题意:
有k个坏人k个好人坐成一圈,前k个为好人(编号1~k),后k个为坏人(编号k+1~2k)
现在有一个报数m,从编号为1的人开始报数,报到m的人就要自动死去。
问当m为什么值时,可以使得在出现好人死亡之前,k个坏人先全部死掉?
PS:当前一轮第m个人死去后,下一轮的编号为1的人 为 前一轮编号为m+1的人
前一轮恰好是最后一个人死掉,则下一轮循环回到开头那个人报“1”
解题思路:
经典的约瑟夫水题
由于k值比较少(1~13),暴力枚举m就可以了
递推公式为:
ans[i]; //第i轮杀掉 对应当前轮的编号为ans[i]的人
ans[0]=0;
ans[i]=(ans[i-1]+m-1)%(n-i+1); (i>1 , 总人数n=2k 则n-i为第i轮剩余的人数)
正规代码
#include<iostream> #include<cstdio> using namespace std; int a[30],ans[30];//第i轮杀掉 对应当前轮的编号为ans[i]的人 int main(){ int n,k,m; while(scanf("%d",&k)==1&&k){ if(a[k]) {printf("%d\n",a[k]);continue;}//方便重复询问(数据范围太小) m=1;//所求的最少的报数 n=2*k;//总人数 for(int i=1;i<=k;i++){ ans[i]=(ans[i-1]+m-1)%(n-i+1);//n-i为剩余的人数,+1从下一个人开始 if(ans[i]<k){//ans[i]=>[0..k) 把好人杀掉了,m值不是所求 i=0; m++;//枚举m值 } } a[k]=m; printf("%d\n",m); } return 0; }
打表写法
#include<cstdio> int k,a[17]={0,2,7,5,30,169,441,1872,7632,1740,93313,459901,1358657,2504881,1245064}; int main(){ while(scanf("%d",&k)==1&&k) printf("%d\n",a[k]); return 0; }
标签:
原文地址:http://www.cnblogs.com/shenben/p/5516149.html