约瑟夫环

约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。

C++递推代码:

#include <iostream>
using namespace std;
int main()
{
    int n,m,f = 0;
    cin >> n;
    cin>>m;
    for (int i = 1; i <= n; i++) f = (f + m) % i;
    cout << f + 1 << endl;
}

参考百度百科:https://baike.baidu.com/item/约瑟夫问题/3857719?fromtitle=%E7%BA%A6%E7%91%9F%E5%A4%AB%E7%8E%AF&fromid=348830&fr=aladdin#2_6

 

非递推:
#include<stdio.h> 
#define N 100
int main() 

    int a[N],i,n,m; 
    printf("请输入这一圈人的数目:"); 
    scanf("%d",&n);
    printf("输入报数的最大值:");
    scanf("%d",&m);
    //开始给这些人编号 
    for(i=0;i<n;i++) 
    { 
        a[i]=i+1; 
    } 
    int j=0;//j用于计数,即让指针后移 
    int l=0;//m记录退出圈子的人数 
    int k=0;//k报数1,2,3 
    while(l<n-1)//当退出的人数不大于总人数时,即留下的人数至少是一个人 
    { 
        if(a[j]!=0)//如果这个人的头上编号不是0就开始报数加1,这里采用的方法是报数为3的人头上编号重置为0 
            k++; 
        if(k==m) 
        { 
            a[j]=0;//将报数为3的人编号重置为0 
            k=0;//报数清零,即下一个人从1开始报数 
            l++; //退出人数加1 
        } 
        j++;//指针后移 
        if(j==n)//如果到了队尾,就要使指针重新指向对头 
            j=0; 
    } 
    printf("剩下的人是:"); 
    int b; 
    for(b=0;b<n;b++) 
    { 
        if(a[b]!=0) 
        { 
            printf("%d号\n",a[b]); 
       } 
    } 
    return 0; 
}  
主要看while里面把j作为标记值即可,适用于小的数。

推广题目:

 

Description  XTU OJ 1051

n个人排成一个圆圈,从第一个人开始,先按顺时针方向,数m,数到m的人退出圆圈,然后从原有方向的下一个人开始,按原来顺序的反方向继续数m,依次数数,直到只剩最后一个人为止。比如有5个人,数3,则依次出去的人为31452,最后的人是2号。现已知nm,请问最后一个人的编号是多少?

输入

       输入数据的第一行为一个整数k,1<=k<=100,表示测试用例的个数。以后每行是两个正整数n,m,1<=n,m<=1000

输出

       输出最后人的编号,每个用例输出一行。

 

Sample Input

2
5 3
5 2
 

Sample Output

2
4
 

Source

ericxie

一开始以为有什么规律,后来放弃了,一步一步来,其实和约瑟夫环是差不多的

#include <stdio.h>
#include <string.h>
int judge[100000];
int main()
{
   int n,a,b,k,temp,i,j,m;
   scanf("%d",&a);
   while(a--)//到只剩一个就跳出
   {
       memset(judge,0,sizeof(judge));
       scanf("%d%d",&n,&m);//n是个数,m是第m个
       bool flag =false;
    temp=n;
       j=1;
       while(--temp)
       {
           k=1;
           flag=!flag;//不断取反,作为标记
        while(k!=m)//判断如果到了第M个,那么就标记j对应的数组为1
        {
            if(flag)//顺时针
            {
             if(j==n)
             j=1;
             else
             j++;
             if(judge[j]==0)
             {k++;
             }
            }
            else//逆时针
            {
               if(j==1)
               j=n;
               else
               j--;
               if(judge[j]==0)
               {k++;
               }
            }
        }
        judge[j]=1;
       }
       for(i=1;i<=n;i++)
       {
           if(judge[i]==0)
           {
           printf("%d\n",i);
           break;
           }
       }
       
   }
}

posted @ 2019-12-27 17:24  adsry  阅读(79)  评论(0)    收藏  举报