读书人

约瑟夫环有关问题结果不对

发布时间: 2012-04-24 14:15:38 作者: rapoo

约瑟夫环问题,结果不对?
/*
约瑟夫环故事背景:
著名犹太历史学家 Josephus有过以下的故事:
在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,
39个犹太人决定宁愿死也不要被敌人抓到,
于是决定了一个自杀方式,41个人排成一个圆圈,
由第1个人开始报数,每报数到第3人该人就必须自杀,
然后再由下一个重新报数,直到所有人都自杀身亡为止。
然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,
他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

解题思路:
将n个人在圈内用1表示,退出用0表示,用一个n长度的一维数组来保存这个约瑟夫环
如果数到n-1个人后再从下一个人开始从1开始数数。
难点:如何判断数到第n-1个人后再循环回到数组起始位置
*/

#include <stdio.h>

void initialize(int n , int a[]);
int source_num(int n, int m, int a[]);
int main(void)
{
int n = 0,m = 0;//n代表人数,m代表从1数到m
int a[100];//最大参与人数不得超过100个
int flag = 0;//记录剩下的人的原始编号

printf("请输入参与人的个数:");
scanf("%d" , &n);
printf("你想到从1数到几:");
scanf("%d" , &m);

initialize(n , a);
flag = source_num(n , m, a);
printf("%d个人参与,剩下的那个人的原始编号为:%d\n" ,n,flag);

return 0;
}
/*将圈内人以代号1表示*/
void initialize(int n , int a[])
{
int i = 0;
for(i = 0;i < n; i++)
{
a[i] = 1;
}
}
/*处理约瑟夫报数问题*/
int source_num (int n, int m, int a[])
{
int i;
int k = 0 , flag=0;//k记录数数过程中的标记,flag记录原始标记号
int exit_num = 0;//记录退出的人数
for(i = 0;i < n;i++)
{
printf("a[%d] = %d\t" ,i, a[i]);
if(a[i] == 1)
{
k+= a[i];//开始数数
if(k == m)
{
k = 0;//如果数到了m则计数器重新开始记数
a[i] = 0;//同时将该位置置0
exit_num++;//退出人数加1
printf("\n");
}
if(exit_num == n - 1)//如果退出人数达到了n-1人,则返回此时的原始标记
{
flag = i + 1;
break;
}

}
/*这里有问题?还没写出来*/
if(i%(n-1) == 0)
{
i = 0;//重新遍历数组
}
}

return flag;

}

[解决办法]
前两年在C版看到过一个相当精简的算法实现,刚才找了下,没找到,找到了另一篇,也不错,如下:
http://topic.csdn.net/u/20090602/13/3878368E-7B47-4937-A383-5ED83CA3A01A.html#r_57448687
[解决办法]

C/C++ code
//假设有n个人团团围做,从第1个人开始数数,数到第m个人时候,第m个人出列,//然后继续从1开始数数,数到第m个人退出#include <stdio.h>#include <conio.h>int i,k,t;int n,m;static char f[1001];//0该座位未出圈,1该座位已出圈void main() {    while (1) {        printf("Input n m(1000>=n>=m>=1):");        fflush(stdout);        rewind(stdin);        if (2==scanf("%d%d",&n,&m)) {            if (1000>=n && n>=m && m>=1) break;        }    }    t=0;//已出圈总人数    i=1;//座位编号    k=1;//当前要数的数    while (1) {        if (0==f[i]) {            if (m==k) {                t++;                f[i]=1;                printf("%3d ",i);                if (0==t%10) printf("\n");                if (t>=n) break;            }            k++;if (k>m) k=1;        }        i++;if (i>n) i=1;    }    cprintf("Press any key ...");    getch();}
[解决办法]
#pragma region 约瑟夫环
//////////////////////////////////////////////////////////////////////////
/************************************************************************/
/*josephu */

/************************************************************************/


int Check(int* nums,int N) //检查是否要经续出圈
{
int i;
for(i=0;i<N;i++)
if (*(nums+i)!=-1)
{
return 1;
}
return 0;
}
//N总人数,M间隔数,start 开始数
void Josp(int N,int M,int start)
{
int *seta;
int i,count=1;
if(start<=1)
start=1;
seta=(int*)malloc(sizeof(int)*N);
for(i=0;i<N;i++)
*(seta+i)=i+1;


while(Check(seta,N))
{
for(i=start-1;i<N;i++)
{
if (*(seta+i)!=-1)
{
if(count==M)
{
printf(" %d",*(seta+i));
*(seta+i)=-1;
count=1;
continue;
}
count++;
}
}
}
}
void josephu()
{
int N,M,start;
scanf("%d %d %d",&N,&M,&start);
Josp(N,M,start);
}
//////////////////////////////////////////////////////////////////////////
#pragma endregion

读书人网 >C语言

热点推荐