生日聚会
Total Submit:55 Accepted:16
Description
今天是JacmY生日,他请大家吃饭,就这样,一行N个人来到了餐馆,大家吃吃喝喝,有说有笑,气氛甚欢,这时突然有人提议大家玩一个游戏,听罢规则后,就开始了游戏。
游戏规则是这样的,吃饭的N个人围坐在桌子旁,JacmY是1号,沿着顺时针方向开始编号,2、3……N,然后由JacmY随机说一个数K(1 <= K <= N),从JacmY开始顺时针报数,“1,2……”,当有人报到K时,这个人从他的位置起来,先坐到了其他桌子,然后由下一个人重新从1开始报……就这样循环下去,每当有人报到K,这个人就离开了桌子,直到剩下这最后一个人,他非常倒霉的要接受大家的惩罚,就是罚酒一杯。JacmY有些郁闷了,K是由自己说的,万一说不好让自己受惩罚了,这个就有点不爽了,所以JacmY想请你帮忙找出哪些K会让他受罚,这样以来,JacmY就不用担心会喝太多酒了!
Input
第一行一个整数T代表样例的组数
下面T行,每行一个整数N, 1 <= N<= 100;N如题目所述。
Output
对于每组数据,第一行输出一个整数M,表示有M个这样的K会让JacmY受罚,接下来一行是M个整数,代表K分别取的哪些值,这些数字间用空格隔开。
Sample Input
3
5
8
10
Sample Output
1
4
2
2 6
1
8
Source
Internet
分析:约瑟夫环。写法多样性。我的写法复杂了!我是按照以前经典算法里的模型写的。后面有一种更快的写法。
此题要注意输出问题。当个数为0是不需要多余的回车,输出k时结尾没有多余的空格。
#include<stdio.h>
//生日聚会
int main()
{
int T, n;
scanf("%d",&T);
while(T --)
{
scanf("%d",&n);
int num = 0, ans[100] = {0};
for(int k=1;k<=n;k++)
{
int man[100] = {0};
int count = 1;
int i = 0, pos = -1;
while(count <= n)
{
do{
pos = (pos+1) % n; // 环状处理
if(man[pos] == 0)
i++;
if(i == k) // 报数为k了
{
i = 0;
break;
}
} while(1);
man[pos] = count;
count ++;
}
if(man[0] == n) // 最后一个
ans[num++] = k;
}
if(num != 0)
{
printf("%d\n",num);
for(int i=0;i<num-1;i++)
printf("%d ",ans[i]);
printf("%d\n",ans[num-1]);
}
else
printf("0\n");
}
return 0;
}
一种更快的写法:
#include<stdio.h>
//生日聚会
int main()
{
int t, n, k;
scanf("%d",&t);
while(t --)
{
scanf("%d",&n);
int num = 0, s = 0;
int ans[10] = {0};
for(k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
s = (s+k)%i;
if(s+1 == 1)
ans[num++] = k;
}
printf("%d\n",num);
if(num != 0)
{
for(int i=0;i<num-1;i++) printf("%d ",ans[i]);
printf("%d\n",ans[num-1]);
}
}
return 0;
}