代码借鉴CSDN大佬https://blog.csdn.net/weixin_41409140/article/details/88071047(对大佬的大佬代码进行分析)
18063 圈中的游戏
时间限制:1000MS 内存限制:65535K
提交次数:0 通过次数:0
题型: 编程题 语言: G++;GCC;VC
Description
有n个人围成一圈,从第1个人开始报数1、2、3,每报到3的人退出圈子。编程使用链表找出最后留下的人。
输入格式
输入一个数n,1000000>=n>0
输出格式
输出最后留下的人的编号
输入样例
3
输出样例
2
----------------------------------------------------------
思路:
/*#include <stdio.h>
#include<stdlib.h>
int c[1000000];
int main()
{ //注意了cur和pre是类似于指针,是一种咱们的“数组指针”,指向的是下标
int i,j,n,pre,cur; //pre为搞死的那个的前一个的下标,cur为搞死那个的下标
scanf("%d",&n);
if(n==1)printf("1
"); //只有一个人都数不了(不可以自己和自己数哦)(毕竟最后是一定要留一个人的就直接输出1就好(但是输入的如果是2的话,
是可以数的了,所以就是1死,二活,所以只有输入1的时候是一个特例,不要认为输入2的时候不够三个人就也是特例了
else
{
for(i=0;i<n-1;i++) c[i]=i+1; //这里外部循环的边界可以是n也可以是n-1,甚至循环2n也是可以的,因为最后一个无论循环多少次都会存在的,就好像就只有一个人一样,是不可以自己和自己数的,所以就输出1 但是如果边界比较小的话就不能保证都筛选完了,所以最好还是n-1以上的(因为一次外部里面就有三次小的循环,每次内部循 环就搞死一个,所以要留一个,也就意味着要搞死n-1个,
所以就要n-1次外部循环才行的,所以外部循环可以是n-1次及以上的
c[n-1]=0; //就是为了方便循环(毕竟也是一个圈,最后一项一般都不是本身,一般都是为了配合圈的操作来定一个比较牛的值,来方便后续的圈操作的
cur=n-1;
for(i=0;i<n-1;i++)
{
for(j=0;j<3;j++)
{
pre=cur; //这个个循环里面其实pre就是记录之后cur指向的下标的的前一个下标的
cur=c[cur]; //核心
}
c[pre]=c[cur]; //cur的数值给了pre的数值
}
printf("%d",pre+1); //由于初始化的时候是把第一项是2,第二项是3,所以要想得到最后的数值的话
//因为我们得到的是下标pre所以就要+1才是它的数值了
}
return 0;
}
*/
无注释代码
1 #include <stdio.h>
2 #include <stdlib.h>
3 int c[1000000];
4 int main()
5 {
6 int i,j,n,pre,cur;
7 scanf("%d",&n);
8 if(n==1)
9 printf("1
");
10 else
11 {
12 for(i=0;i<n-1;i++)
13 c[i]=i+1;
14 c[n-1]=0;
15 cur=n-1;
16 for(i=0;i<n-1;i++)
17 {
18 for(j=0;j<3;j++)
19 {
20 pre=cur;
21 cur=c[cur];
22 }
23 c[pre]=c[cur];
24 }
25 printf("%d",pre+1);
26 }
27 return 0;
28 }
1 #include<stdio.h>
2 #include<stdlib.h>
3 int cj(int n,int m)
4 {
5 int p=0;
6 int i;
7 for(i=2;i<=n;i++)
8 {
9 p+=(p+m)%i;//这个方法的话就不用单独的讨论n=1的情况了,因为在这个函数里面。如果n=1的话是不会进行循环里面的,也就是最后是会返回1的
10 }
11 return p+1
12 }
13 int main()
14 {
15 int n,m;
16 scanf("%d",&n);
17 m=3;
18 int ans;
19 ans=cj(n,m);
20 printf("%d",ans);
21 }
虽然方法一是很难想到的,没有像方法二那麽好理解的,但是这个方法是可以用在如果他是选的不是第1位的开始数的话就不行了呢
比如1139 约瑟夫环问题
1139 约瑟夫环问题
时间限制:500MS 内存限制:65536K
提交次数:157 通过次数:79
题型: 编程题 语言: G++;GCC
Description
约瑟夫(josephus)环是这样的:假设有n个小孩围坐成一个圆圈,并从1开始依次给每个小孩编上号码。老师指定从第s位小孩起从1开始报数,
当数到m时,对应的小孩出列,依次重复,问最后留下的小孩是第几个小孩?例如:总共有6个小孩,围成一圈,从第一个小孩开始,
每次数2个小孩,则游戏情况如下:
小孩序号:1,2,3,4,5,6
离开小孩序号依次为:2,4,6,3,1
最后获胜小孩序号:5
输入格式
每组输入是三个整数n,s,m。(1 <= n <= 30, 1 <= s <= n,1 <= m <= 10) ;
输出格式
对于每组输入,请输出最后留下小孩的序号。
输入样例
6 1 2
输出样例
5
/********这里就是m就不再是3了,所以就只用改变一下内层的for的边界即可了
然后是从s开始的话,由于上面的代码都是从1开始的,但是画图发现,从s开始的话,答案其实就是从1开始的答案再+(s-1)也就是s和1的差,因为是按序的编号的,所以是可以的
具体代码:********
1 #include<stdio.h> 2 #include<stdlib.h> 3 int c[30]; 4 int main() 5 { 6 int i,j,pre,n,cur,s,m; 7 scanf("%d %d %d",&n,&s,&m); 8 if(n==1) 9 printf("1 "); 10 else 11 { 12 for(i=0;i<n-1;i++) 13 c[i]=i+1; 14 } 15 c[n-1]=0; 16 cur=n-1; 17 for(i=0;i<=n-1;i++) 18 { 19 for(j=0;j<3;j++) 20 {pre=cur; 21 cur=c[cur]; 22 } 23 c[pre]=c[cur]; 24 } 25 printf("%d",pre+s);//由于板子里面的是pre+1.然后我们要上加s-1,所以1和-1抵消了,所以就是直接的就s+pre即可了 26 }*/