PKU1012:Joseph
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 30210 | Accepted: 11259 |
Description
Suppose that there are k good guys and k bad guys. In the circle the first k are good guys and the last k bad guys. You have to determine such minimal m that all the bad guys will be executed before the first good guy.
Input
Output
Sample Input
340
Sample Output
530
原题地址:http://acm.pku.edu.cn/JudgeOnline/problem?id=1012
____________________________________________________________________________________________________________________________
题解:
1、原始约瑟夫问题:
问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。
题解:
第一个人(编号一定是m mod n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m mod n的人开始):k k+1 k+2 ... n-2, n-1, 0, 1, 2, ... k-2 并且从k开始报0。 现在我们把他们的编号做一下转换:
k --> 0
k+1 --> 1
k+2 --> 2
...
...
k-2 --> n-2
变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去就是n个人情况的解。
变回去的公式:x'=(x+k) mod n
通过递推可求出最后获胜人的编号。
2、本题网上搜到的解法
对于本题,设F[i]为第i轮出去人的编号,那么:
F[1]=(m-1) MOD n;
F[2]=(F[1]+m-1) MOD (n-1)
...
F[i]=(F[i-1]+m-1) MOD (n+1-i)
只要判断F[i]<K即可。
考虑最后2轮情况:{a a ... a b b}(第k-1轮) => {a a ... a b}(第k轮) => {a a ... a}
如果M(k-1)=k则M(k)=k,如果M(k-1)=k+1则M(k)=k+1
所以m测试值可以取k+2和k+1的倍数。
【个人理解:实际上,F[I]的公式是有问题的,并未考虑到已经不存在的人的位置,因此单独用这个公式是有问题的。】
3、我的解法
1 for (i=1;i<=k;i++)
2 {
3 out=(m-1)%(n+1-i);//第I轮出局的人在第I轮的编号
4 for (j=1;j<=i-1;j++)//算出第I轮出局的人的初始编号
5 out=(out+1+(m-1)%(n+1-i+j))%(n+1-i+j);
6 if (out<=k-1) return 0;
7 }
代码:
因为要算出所有出局人的编号,所以有点慢。
1 #include<stdio.h>
2 int ans[14];
3 int k,m;
4 int joseph(int n)
5 {
6 int i,j,out;
7 for(i=1;i<=k;i++)
8 {
9 out=(m-1)%(n+1-i);//第I轮出局的人在第I轮的编号
10 for (j=1;j<=i-1;j++)//算出第I轮出局的人的初始编号
11 out=(out+1+(m-1)%(n+1-i+j))%(n+1-i+j);
12 if (out<=k-1) return 0;
13 }
14 return 1;
15 }
16 int main()
17 {
18 for (k=1;k<=13;k++)
19 {
20 m=1;
21 while (joseph(2*k)==0) m++;
22 ans[k]=m;
23 }
24 scanf("%d",&k);
25 while (k)
26 {
27 printf("%d\n",ans[k]);
28 scanf("%d",&k);
29 }
30 return 0;
31 }
32