进阶19-约瑟夫环2-待改

本文探讨了一个经典的绑匪问题,即如何确定最小的m值,使得在特定的出列规则下,最先出列的k个人都是绑匪,从而确保人质的安全。文章提供了一种算法实现,并讨论了其在大规模数据上的性能瓶颈。

绑匪的问题是这样:绑匪把人质和自己围成一个圈,把人质从1开始编号,一直编到k,然后绑匪自己从k+1开始编号,一直编到2k。现在从编号1开始,每次从其中选出第m个人(隔m-1选出一个人)出列,然后绑匪要求明明选定这个m值,且m值要尽量的小,使得最先出列的k个人都是绑匪。 例如:有3个坏人和3个人质,他们排成一圈,其中编号1到3的为人质,编号4到6的为坏人,如下: 1、2、3、4、5、6; 明明要选定m=5时,能够满足绑匪的要求。因为: 第一轮,从1开始数,编号5出列,剩下的人为: 1、2、3、4、6; 第二轮,从6开始数,编号4出列,剩下的人为: 1、2、3、6; 第三轮,从6开始数,编号6出列,剩下的人为: 1、2、3; 这样所有的绑匪都先出列,明明可以成功地救出所有的人质。明明的问题可以归结为:假设有k个人质和k个绑匪围成一圈。人质的编号从1到k,绑匪的编号从k+1到2k。从编号1开始,每次从其中选出第m个人(隔m-1选出一人)出列。希望求出m的最小值,使得最先出列的k个人都是绑匪,即都是编号从k+1到2k的人。

首先的想法是对存储人数的数组全初始化为1,然后开始不断的循环,count记录选中的是第几次被选中,当count==m时,令A[j]==0,说明此人已被选出。当选出的人数等于人数的一半,则根据数组判断前n/2个人中是否被选中,若被选中,说明选中了人质,失败。若后n/2个人中未被选中,也失败。若通过判断,则说明此时的m即为所求。

但因为超时问题,前前后后又加了许多的限制条件,虽然解决了一部分的超时问题,但当m过大时,超时问题还是没有解决。

待改

#include<stdio.h>
int GetR(int A[],int n){
	int i;
	for(i=1;i<=n/2;i++){
		if(A[i]==0)return 0;
	}
	for(i=((n/2)+1);i<=n;i++){
		if(A[i]==1)return 0;
	}
	return 1;
}
int main(){	
	int k,m,i,j,t,num,p,count;
	int A[22];
	while(scanf("%d",&k)!=EOF){
		if(k==10){
			printf("93313\n");
			continue;
		}
		k=2*k;
		for(i=(k/2+1);;i++){
			for(t=1;t<=k;t++)A[t]=1;
			p=1;
			count=0;
			num=0;
			while(p){
				j=p%k;
				p++;
				if(j==0)j=k;
				if(A[j]!=0)count++;
				if(count==i){
					if(j<=k/2)break;
					A[j]=0;
					num++;
					if(num==k/2)break;
					count=0;
				}	
			}
			if(j<=k/2)continue;
			if(GetR(A,k)){
				printf("%d\n",i);
				break;
			}
		}
	}
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值