/*约瑟夫两种递归的区别(一个求最后活下来的,一个求的是死掉的人位置)
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;
}