您的位置:首页 > 其它

关于 约瑟夫环 问题

2013-03-12 16:10 295 查看
/* 此处借助九度oj上的题目!



题目描述:

每年六一儿童节,JOBDU都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为JOBDU的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为1的小朋友开始报数。每次喊到m的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续1...m报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到JOBDU名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?

输入:

输入有多组数据。

每组数据一行,包含2个整数n(0<=n<=1,000,000),m(1<=m<=1,000,000),n,m分别表示小朋友的人数(编号1....n-1,n)和HF指定的那个数m(如上文所述)。如果n=0,则结束输入。

输出:

对应每组数据,输出最后拿到大奖的小朋友编号。

*/



本质就是 约瑟夫环



我们一般的约瑟夫环的思路是:先建立环,然后在绕圈子,代码入如下:

#include <stdio.h>

typedef struct link

{

long id;

struct link * next;

}link, *p_link;

int main()

{

long n, m, count, i;

p_link head;

p_link tmp, t;



while( scanf("%ld", &n) != EOF )

{

if( !n )

{

break;

}



scanf("%ld", &m);



head = ( p_link )malloc( sizeof( link ) );

head->id = 1;

head->next = head;



t = head;

for( i = 1; i < n; i++ )

{

tmp = ( p_link )malloc( sizeof( link ) );

tmp->id = i + 1;

tmp->next = t->next;

t->next = tmp;

t = tmp;

}

count = 0;

tmp = head;

while( n > 1 )

{

count++;

if( count == m )

{

n--;

// printf("%d ", tmp->id);

count = 0;

tmp->id = tmp->next->id;

t = tmp->next;

tmp->next = t->next;

free( t );

}

else

{

tmp = tmp->next;

}

}



printf("%ld\n", tmp->id);

}



return 0;

}

当数据量很大的时候,上述算法消耗时间很多!所以改进如下!;

第一个人(编号一定是(m)%n) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环:

  k k+1 k+2 ... n-2, n-1, n, 1, 2, ... k-2

(以编号为k = ( m +1)%n的人开始)

  并且从k开始报1。

  现在我们把他们的编号做一下转换:( 这是核心 )

  k --> 1

  k+1 --> 1

  k+2 --> 3

...........................................

  k-3 --> n-1

  k-2 --> n

  序列1: 1, 2, 3 … n-2, n-1, n

  序列2:1, 2, 3 … k-1, k+1, …, n-2, n-1, n

  序列3: k, k+1, k+2, k+3, …, n-2, n-1,n, 1, 2, 3,…, k-1

  序列4: 1, 2, 3 …, 5, 6, 7, 8, …, n-3, n-2,n-1

成为了(n-1)个人报数的子问题,这里就是递归的思想!!!!

我们可以得到:

   f[i] = ( f[i-1] + m) % i; ( i > 1 ) ( %i的原因是:因为每一次的i都是一个子问题,呵呵~ )

#include <stdio.h>

int main()

{

int n,m,i,r;

while(scanf("%d",&n) == 1)

{

if( !n )

{

break;

}



scanf("%d",&m);

r = 0;

for( i = 2; i <= n; i++ )

{

r = (r + m) %i; // 这里!!!!

}

printf("%d\n",r + 1);

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: