约瑟夫

/*约瑟夫两种递归的区别(一个求最后活下来的,一个求的是死掉的人位置)
1. (1)s=0;
   for (i=2;i<=n;i++) 
    s=(s+m)%i;      
   (2)s=0;
   for (i=2;i<=n;i++)
	 s=(s+m-1)%n;
   if(s==0) s=n-1; //循环结束s+1为存活的人
2.s=0;
  while(1)
  {
     s=(s+m-1)%n //此时s的值就为死掉的位置(不是死掉的号码) 
     n--;
先引入Joseph递推公式,设有n个人(0,...,n-1),数m,则第i轮出局的人为f(i)=(f(i-1)+m-1)%(n-i+1),f(0)=0; f(i) 表示当前子序列中要退出的那个人(当前序列编号为0~(n-i));
 
拿个例子说:K=4,M=30;
 
f(0)=0;
f(1)=(f(0)+30-1)%8=5; 序列(0,1,2,3,4,5,6,7)中的5
f(2)=(f(1)+30-1)%7=6; 序列(0,1,2,3,4,6,7)中的7
f(3)=(f(2)+30-1)%6=5; 序列(0,1,2,3,4,6)中的6
f(4)=(f(3)+30-1)%5=4; 序列(0,1,2,3,4)中的4
*/ 

 

n个人想玩残酷的死亡游戏,游戏规则如下: n个人进行编号,分别从1到n,排成一个圈,
顺时针从1开始数到m,数到m的人被杀,剩下的人继续游戏,活到最后的一个人是胜利者。 
请输出最后一个人的编号。
*/

#include <stdio.h>
int main(int argc, char *argv[])
{
	int n,m,i,s=0;
	scanf("%d%d",&n,&m);
	for (i=2;i<=n;i++)
	{
		s=(s+m)%i;
	}
	printf("%d",s+1);
	return 0;
}


 

/*n个人围坐一圈,并按顺时针方向1—n编号。从第s个人开始进行报数,报数到第m个人,此人出圈,
再从他的下一个人重新开始从1到m的报数进行下去 ,直到只剩一个人为业
人数n
从第s个人开始报数1
报到第几个数m
*/

#include <stdio.h>
int main(int argc, char *argv[])
{
	int n,m,s,f[100],i,t,k;
	scanf("%d",&n);
	scanf("%d",&s);
	scanf("%d",&m);
	k=1;
	t=0;
	for (i=s;i<=n;i++)
	  f[k++]=i;
	for (i=1;i<s;i++)
	  f[k++]=i;       //将第s个数对应序号为1的位置 
	for (int i=2;i<=n;i++)
	   t=(t+m)%i;
	   printf("%d",f[t+1]);
	return 0;
}


 

/*
 poj 1012
 输入k 前k个好人后k个坏人,总共2k个人 求最小的m使最后一个坏人死前好人一个不死 
  由于前k个人都不死,所以前k的人位置号码不会发生变动,因此(s+1)的位置<k不成立
*/ 
#include <stdio.h>
int main(int argc, char *argv[])
{
	int n,m,i,s=0,flag,k;
	int a[14];
	int T=0;	
	for (i=1;i<14;i++)
    {   
	    m=1;
	    flag=0;
	    while(1)
	   {
	   	 n=2*i;
	   	 s=0;
	     while(1)
	     {
     	      s=(s+m-1)%n;
			  n--;
			  if(s+1<=i) break;
			  if(n==i)	{ flag=1; break;}
     	 }
     	 if(flag==1) break;
     	 m++;
	   }  
	   a[i]=m;
	}
	while(scanf("%d",&k) && k)
	{
		printf("%d\n",a[k]);
	}
	return 0;
}


 

/*poj 3750 
 小孩报数问题
第一行输入小孩的人数N(N<=64) 
接下来每行输入一个小孩的名字(人名不超过15个字符) 
最后一行输入W,S (W < N),用逗号","间隔
Output

按人名输出小孩按顺序出列的顺序,每行输出一个人名
Sample Input

5
Xiaoming
Xiaohua
Xiaowang
Zhangsan
Lisi
2,3
*/
#include <stdio.h>
#include<string.h>
int main(int argc, char *argv[])
{
	int n;
	char nameW[65][15],name[64][15];
	int w,s;
	int k,i,t;
	while(scanf("%d",&n)==1)
	{

		for(i=1;i<=n;i++)
		  scanf("%s",nameW[i]);//输入名字 注意赋i=1方便 
		scanf("%d,%d",&w,&s);
		k=0;
		for(i=w;i<=n;i++)
		  strcpy(name[k++],nameW[i]);
		for (i=1;i<w;i++)
		  strcpy(name[k++],nameW[i]);//令第w个的人的位置变为1 
		t=0;  
        while(1)
		{
			t=(t+s -1)%n;
			n--;
		    printf("%s\n",name[t]);
		    k=n-t;//由于前面n--了 所以这里无需再减1 
		    int  T=t;//防止t发生改变 
			while(k--)//当该人输出后,后面的人位置顶上去 
		    {
			  strcpy(name[T],name[T+1]);
			  T++;
			}
			if(n==0) break;
		}      
	} 
	return 0;
}



 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值