主题:[讨论]编写一算法解决约瑟夫问题
人魚◎泡泡
[专家分:0] 发布于 2007-03-14 15:07:00
设有N个人为坐在圆桌周围,现从第S个人开始报数,数到第M个人出列,然后从出列的下一个人重新开始报数,数到第M个人又出列……如此重复直到所有的人全不出列为止,例如当N=8,M=4,S=1,得到的新序列为:4,8,5,2,1,3,7,6
回复列表 (共25个回复)
11 楼
人魚◎泡泡 [专家分:0] 发布于 2007-03-20 11:37:00
6楼太帅了,程序完全正确啊,可惜用的是很一般的C语言的做的,我们老是要求我们用链表来做啊,拜托啦
12 楼
人魚◎泡泡 [专家分:0] 发布于 2007-03-20 11:38:00
6楼太帅了,可是用链表应该怎么做呢?
13 楼
雨中飞燕 [专家分:18980] 发布于 2007-03-20 19:22:00
[quote]
6楼太帅了,程序完全正确啊,可惜用的是很一般的C语言的做的,我们老是要求我们用链表来做啊,拜托啦[/quote]
这是你的作业题???
1楼的程序没有问题啊,你怎么会得出那个结果的?
14 楼
人魚◎泡泡 [专家分:0] 发布于 2007-03-20 22:05:00
我是一个字一个字敲进去的,调试的时候真的有问题啊
15 楼
wangfangbob [专家分:380] 发布于 2007-03-21 10:08:00
一楼算法证明:
假设数到第p个数时遇到的数,和数到第x个数到遇到的数一样,且p - n < x < p,而且x % m != 0, 否则会被跳过和第个p数遇到的数肯定不一样,那么说明数了x个数之后再数一圈就数到了第p个数,而数一圈数过的数应该是n减去要跳过的数,因为已经数过了x个数,所以要跳过[x / m]个数( []表示取整数部分 ),所以x + n - [x / m] = p
问题转化为: p - n = x - [x / m]...(1),且 x % m != 0, p - n < x < p, 求解x
因为x % m != 0 => x / m - 1 < [x / m] < x / m
=> x - x / m + 1 > x - [x / m] > x - x / m
=> [x - x / m + 1] >= x - [x / m] > [x - x / m]
=> [x - x / m] + 1 >= x - [x / m] > [x - x / m]
=> [x - x / m] + 1 >= x - [x / m] >= [x - x / m] + 1
=> [x - x / m] + 1 = x - [x / m]
( 代入(1)式 )=> p - n - 1 = [x - x / m] = [x * ( m - 1 ) / m] ... (2)
因为x % m !=0 且 ( m - 1 ) % m != 0 => ( x * ( m - 1 ) ) % m != 0
由(2)式 => 0 < x * ( m - 1 ) - m * ( p - n - 1 ) <= m - 1
由左边: => m * ( p - n - 1 ) < x * ( m - 1 )
=> m * ( p - n - 1 ) / ( m - 1 ) < x
=> [m * ( p - n - 1 ) / ( m - 1 )] < x
=> [m * ( p - n - 1 ) / ( m - 1 )] + 1 <= x ...(3)
由右边: => x * ( m - 1 ) - ( m - 1 ) <= m * ( p - n - 1 )
=> ( x - 1 ) * ( m - 1 ) <= m * ( p - n - 1 )
=> x - 1 <= m * ( p - n - 1 ) / ( m - 1 )
=> x - 1 <= [m * ( p - n - 1 ) / ( m - 1 )]
=> x <= m * ( p - n - 1 ) / ( m - 1 ) + 1 ...(4)
由(3),(4) => x = [m * ( p - n - 1 ) / ( m - 1 )] + 1
= [ p - n - 1 + ( p - n - 1 ) / ( m - 1 )] + 1
= p - n - 1 + [( p - n - 1 ) / ( m - 1 )] + 1
= p - n + [( p - n - 1 ) / ( m - 1 )]
由于计算机算整数除法直接就取整了,所以递归时就写成
p = p - n + ( p - n - 1 ) / ( m - 1 )
16 楼
wangfangbob [专家分:380] 发布于 2007-03-21 10:11:00
楼主,不好意思,偶目前还没学到链表,过两天买了严蔚敏的数据结构才能给你解决,假如你不着急的话,还有,我的程序还能简化:
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
int i,j,result, N, M, S;
scanf("%d%d%d", &N, &M, &S);
for ( i = 1; i <= N; ++i )
{
for ( j = 1, result = 0; j <= i; ++j )
result = ( M + result - 1 ) % ( N + j - i ) + 1;
result = ( result + S - 2 ) % N + 1;
printf("%d\n", result );
}
system("pause");
}
17 楼
wangfangbob [专家分:380] 发布于 2007-03-21 17:12:00
我看了一点我的书的最后一章的链表知识,写了个约瑟夫环的链表解
因为还没系统学,可能很不规范,楼主将就看吧
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
int i, j, n, m, s;
struct jos
{
int num;
struct jos* next;
};
scanf( "%d%d%d", &n, &m, &s );
struct jos round[n]; // 要是你的编译器不支持变长数组的话就用malloc
struct jos* tmp = &round[s - 1];
for ( i = 0; i < n - 1; ++i )
{
round[i].num = i + 1;
round[i].next = &round[i + 1];
}
round[n - 1].num = n;
round[n - 1].next = &round[0];
for ( i = 0; i < n; ++i )
{
for ( j = 0; j < m - 2; ++j )
tmp = tmp -> next;
//因为tmp指向数数字1的节点,跳过m-2个,指向了要删除的节点的前一个节点
printf( "%d\n", tmp -> next -> num );
tmp -> next = tmp -> next -> next; //删除节点
tmp = tmp -> next; //再次指向数数字1的节点
}
system( "pause" );
return 0;
}
18 楼
人魚◎泡泡 [专家分:0] 发布于 2007-03-22 15:12:00
#include<stdio.h>
#include<alloc.h>
typedef struct node
{
elemtype data;
struct node *next;
}Lnode;
typedef int elemtype;
Lnode *creat()
{
Lnode *h,*p;
elemtype y,x;
h=(Lnode*)malloc(sizeof(Lnode));
h->next=NULL;
do
{
x=0;
scanf("%d\n",&y);
if(y<0)
printf("error\n");
else
{p=(Lnode*)malloc(sizeof(Lnode));
p->data=y;
p->next=h->next;
h->next=p;
}
x++;
}while(x>y);
return(h);
};
int main(void)
{
int i, j,n,result,m,s;
scanf("%d%d%d",&n,&m,&s);
for(i=1;i<=n;++i)
{
for(j=1,result=0;j<=i;++j)
{
result=(m+result)%(n+j-i);
result=(0==result)?(n+j-i):result;}
result=(result+s-1)%n;
result=(result==0)?n:result;
printf("%d\n",result);
}
system("pause");
}
19 楼
人魚◎泡泡 [专家分:0] 发布于 2007-03-22 15:13:00
我写的链表,有点问题,但是我太笨了,找不出来,帮忙哈
20 楼
bpttc [专家分:8790] 发布于 2007-03-24 21:39:00
http://bpttc.blog.sohu.com/33526250.html
楼主看我blog里的模拟方法解约瑟夫环,里面有采用循环链表方法
刚刚重新写了一下,在devcpp里测试通过
我来回复