poj 1012

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]);

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值