简单的约瑟夫问题:使用数组,模拟一个圈,每次数到m就标记为已读,num=0

接着从下一个人开始,如果到了最后一个人,就重新回到第一个人,继续开始寻找,如果没有被标记过num(数到的数字)++,直到所有人都退出圈子结束

源代码

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 int main()
 6 {
 7     int n,m;
 8     bool vis[1000];
 9     int num=0,ans=0;
10     memset(vis,0,sizeof(vis));
11     scanf ("%d%d",&n,&m);
12     for (int i= 1;i <= n+1;i++)
13     {
14         if (i==n+1)
15             i=1;
16         if (vis[i]==0)
17             num++;
18         if(num==m)
19         {
20             ans++;
21             printf ("%d ",i);
22             vis[i]=1;
23             num=0;
24         }
25         if (ans==n)
26         break;
27     }
28     return 0;
29 }

已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。
例如:n = 9, k = 1, m = 5
【解答】
出局人的顺序为5, 1, 7, 4, 3, 6, 9, 2, 8。

第一种变法,从第k个人开始数,即把循环的初始值设为k即可

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 int main()
 6 {
 7     int n,m,k;
 8     bool vis[1000];
 9     int num=0,ans=0;
10     memset(vis,0,sizeof(vis));
11     scanf ("%d%d%d",&n,&m,&k);
12     for (int i= k;i <= n+1;i++)
13     {
14         if (i==n+1)
15             i=1;
16         if (vis[i]==0)
17             num++;
18         if(num==m)
19         {
20             ans++;
21             printf ("%d ",i);
22             vis[i]=1;
23             num=0;
24         }
25         if (ans==n)
26         break;
27     }
28     return 0;
29 }

编号为1,2,....,N的N个人按顺时针方向围坐一圈,每人持有一个密码(正整数).一开始任选一个正整数作为报数上限值M,从第一个人开始按顺时针方向自1开始顺序报数,报到M时停止报数.报M的人出列,将他的密码作为新的M值,从他在顺时针方向上的下一个人开始 重新从1报数,如此下去,直至所有人全部出列为止.试设计一个程序求出出列顺序.

测试数据:
N=7;7个人 的密码依次为:3,1,7,2,4,8,4,首先M值为6(正确的出列顺序应为6,1,4,7,2,3,5)

变式2:仍从第一个人开始数,只是每一次m都要重新更新,我们就在每次数到当前m的同时,将m更新

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 int main()
 6 {
 7     int n,m;
 8     int a[1000];
 9     bool vis[1000];
10     int num=0,ans=0;
11     memset(vis,0,sizeof(vis));
12     scanf ("%d%d",&n,&m);
13     for (int i = 1;i <= n;i++)
14     scanf ("%d",&a[i]);
15     for (int i= 1;i <= n+1;i++)
16     {
17         if (i==n+1)
18             i=1;
19         if (vis[i]==0)
20             num++;
21         if(num==m)
22         {
23             ans++;
24             printf ("%d ",i);
25             vis[i]=1;
26             num=0;
27             m=a[i];
28         }
29         if (ans==n)
30         break;
31     }
32     return 0;
33 }

n个人排成一圈。从某个人开始,按顺时针方向依次编号。从编号为1的人开始顺时针“一二一”报数,报到2的人退出圈子。这样不断循环下去,圈子里的人将不断减少。由于人的个数是有限的,因此最终会剩下一个人。试问最后剩下的人最开始的编号。
输入格式 Input Format
一个正整数n,表示人的个数。输入数据保证数字n不超过100。
输出格式 Output Format
一个正整数。它表示经过“一二一”报数后最后剩下的人的编号。
样例输入 Sample Input :9
样例输出 Sample Output:3

围绕着山顶有10个洞,狐狸要吃兔子。

兔子说:“可以,但必须找到我,我就藏身于这十个洞中,你从10号洞出发,先到1号洞找,第二次隔1个 洞找,第三次隔2个洞找,以后如此类推,次数不限。”

 但狐狸从早到晚进 进出出了1000次,仍没有找到兔子。问兔子究竟藏在哪个洞里? 

约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。

例如N=6,M=5,被杀掉的人的序号为5,4,6,2,3。最后剩下1号。
假定在圈子里前K个为好人,后K个为坏人,你的任务是确定这样的最少M,使得所有的坏人在第一个好人之前被杀掉。

12-26 19:07
查看更多