JOSEPHS
原题大意:
k个好人和k个坏人构成一个约瑟夫环,要求在k轮将所有坏人清场,求每次叫号的人数。
这道题是约瑟夫的变形,众所周知,如果我们用循环链表的这样方便的数据结构做的话是完全费事的。
在我们列举了一些数据之后发现一个规律:
f(i)=(f(i-1)+m-1)%(n-i+1);
这里i是进行的轮数,n是总人数,m是叫号数。
我们就可以根据这一规律进行一个一个的匹配,将m用循环求出。
匹配的要求是什么呢,
坏人在最后,所以F(i)的值必须大于k。
所以代码如下:
#include<stdio.h>
int josephs(int k,int m)
{
int n=2*k,s=0,i;
for(i=1;i<=k;i++)
{
s=(s+m-1)%(n-i+1);
if(s<k)
return 0;
}
return 1;
}
int main()
{
int k,m,a[14],i;
while(scanf("%d",&k),k)
{
//i+=k+1保证如果这次是小于k,加上k+1会在>k for(i=k+1;;i+=k+1)
{
if(josephs(k,i))
{
a[k]=i;
break;
}
else if(josephs(k,i+1))
//确定第k+1个必须先确定k的位置 {
a[k]=i+1;
break;
}
}
printf("%d\n",a[k]);
}
}
虽然已在循环范围上做出优化但是很遗憾还是超时。
最后只能用打表的方式将所有结果用数组存下来。
#include<stdio.h>
int main()
{
int num[15] = { 0, 2, 7, 5, 30, 169, 441, 1872, 7632, 1740, 93313, 459901, 1358657, 2504881 };
while(scanf("%d",&k),k)
printf("%d\n",num[k]);
}