PKU1012:Joseph

Joseph
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 30210 Accepted: 11259

Description

The Joseph's problem is notoriously known. For those who are not familiar with the original problem: from among n people, numbered 1, 2, . . ., n, standing in circle every mth is going to be executed and only the life of the last remaining person will be saved. Joseph was smart enough to choose the position of the last remaining person, thus saving his life to give us the message about the incident. For example when n = 6 and m = 5 then the people will be executed in the order 5, 4, 6, 2, 3 and 1 will be saved.

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

The input file consists of separate lines containing k. The last line in the input file contains 0. You can suppose that 0 < k < 14.

Output

The output file will consist of separate lines containing m corresponding to k in the input file.

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)=kM(k)=k,如果M(k-1)=k+1M(k)=k+1
所以m测试值可以取k+2k+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

 

posted on 2010-07-28 12:01  风也轻云也淡  阅读(102)  评论(0编辑  收藏  举报