用单循环链表来玩一下约瑟夫环游戏

一群小孩围成一圈,每个小孩都会带有一个随机的密码。然后设定一个数m,从第一个小孩数起,数到第m个的时候,该小孩离开。小孩离开时,其携带的密码将更新这个m值,顺序往下数的第m个小孩会继续出列。依次这样数下去,最后一个小孩是胜利者,问:胜利者是第几个小孩?

这就是大家所熟知的约瑟夫环

循环链表天然地很适合解决这个问题,下面用C语言实现了一下:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <time.h>
  4 #define OK 1;
  5 #define ERROR 0;
  6 #define OVERFLOW -2;
  7 
  8 typedef int ElemType;
  9 typedef struct Node
 10 {
 11     ElemType num;
 12     ElemType password;
 13     struct Node *next;
 14 }Node;
 15 typedef struct Node CLinkList; /* 定义LinkList */
 16 
 17 void main(){
 18     int num=10;
 19     int m=10;
 20     CLinkList *L;
 21     /* 输入约瑟夫环的总结点数*/
 22     printf("有多少个小孩参与游戏(设定小于100):");
 23     scanf("%d",&num);
 24     if(num<=0||num>=100){
 25         /* 如果输入的数字超出范围,就默认总结点数为10 */
 26         printf("你的输入不符合,下面采用默认数字10\n");
 27         num=10;
 28     }
 29     /* 输入第一个需要出列的数字 */
 30     printf("第一个报到哪个数必须出列 (设定小于100):");
 31     scanf("%d",&m);
 32     if(m<=0||m>=100){
 33         printf("你的输入不符合,下面采用默认数字10\n");
 34         m=10;
 35     }
 36     InitList(L);
 37     Creat_Joseph(L,num);
 38     ListTraverse(L,num);
 39     Joseph_Run(L,m);
 40 }
 41 
 42 /* 释放删除的结点 */
 43 void FreeNode(CLinkList *p){
 44     CLinkList *temp=p;
 45     while(temp->next!=p)
 46         temp=temp->next;
 47     temp->next=p->next;
 48     printf("编号%3d的小孩离队了,他携带的密码是%3d\n",p->num, p->password);
 49     free(p);
 50 }
 51 
 52 /* 初始化结点 */
 53 int InitList(CLinkList *l){
 54     l=(CLinkList *) malloc (sizeof(CLinkList));
 55     if(!l)
 56         return OVERFLOW;
 57     return OK;
 58 }
 59 /* 创建每个结点携带的密码 */
 60 void Creat_Joseph(CLinkList *l,int length){
 61     int i;
 62     CLinkList *p=l;
 63     l->next=l;
 64     l->num=1;
 65     srand( (unsigned)time(NULL));
 66     l->password=rand()%(length+3)+1;
 67     printf("以下小孩(约瑟夫环结点)携带的密码随机生成的:\n");
 68     /* 打印约瑟夫环的第一个结点 */
 69     printf("小孩编号: %3d      带的密码: %3d\n",l->num,l->password);
 70     for(i=1;i<length;i++){
 71         CLinkList* temp=(CLinkList*)malloc (sizeof(CLinkList));
 72         p->next=temp;
 73         temp->next=l;
 74         temp->num=i+1;
 75         temp->password=rand()%(2*length)+1;
 76         /* 打印除第一个结点外的其它结点 */
 77         printf("小孩编号: %3d      带的密码: %3d\n",temp->num,temp->password);
 78         p=p->next;
 79     }
 80 }
 81 
 82 void ListTraverse(CLinkList *L,int length)
 83 {
 84     int i;
 85     CLinkList *p=L->next;
 86     for(i = 0; i < length; i++)
 87     {
 88         printf("%d:%d ",p->num, p->password);
 89         p=p->next;
 90     }
 91     printf("\n");
 92     return OK;
 93 }
 94 
 95 /* 根据结点携带的密码释放下一个结点 */
 96 void Joseph_Run(CLinkList *l, int m){
 97     int i,k;
 98     CLinkList *temp,*p;
 99     if(l->next==l)
100         /* 打印最后一个结点 */
101         printf("最后编号 %d 的小孩获胜!",l->num);
102     else{
103         temp = l;
104         for(i=1; i<m; i++)
105         {
106             printf("编号%3d的小孩安全\n",temp->num);
107             temp=temp->next;
108         }
109         p=temp->next;
110         k=temp->password;
111         /* 释放中招的结点 */
112         FreeNode(temp);
113         /* 递归 */
114         Joseph_Run(p,k);
115     }
116 }

程序运行结果:

有多少个小孩参与游戏(设定小于100):6
第一个报到哪个数必须出列 (设定小于100):8
以下小孩(约瑟夫环结点)携带的密码随机生成的:
小孩编号:   1      带的密码:   5
小孩编号:   2      带的密码:   9
小孩编号:   3      带的密码:  12
小孩编号:   4      带的密码:   2
小孩编号:   5      带的密码:   5
小孩编号:   6      带的密码:   2
2:9 3:12 4:2 5:5 6:2 1:5
编号  1的小孩安全
编号  2的小孩安全
编号  3的小孩安全
编号  4的小孩安全
编号  5的小孩安全
编号  6的小孩安全
编号  1的小孩安全
编号  2的小孩离队了,他携带的密码是  9
编号  3的小孩安全
编号  4的小孩安全
编号  5的小孩安全
编号  6的小孩安全
编号  1的小孩安全
编号  3的小孩安全
编号  4的小孩安全
编号  5的小孩安全
编号  6的小孩离队了,他携带的密码是  2
编号  1的小孩安全
编号  3的小孩离队了,他携带的密码是 12
编号  4的小孩安全
编号  5的小孩安全
编号  1的小孩安全
编号  4的小孩安全
编号  5的小孩安全
编号  1的小孩安全
编号  4的小孩安全
编号  5的小孩安全
编号  1的小孩安全
编号  4的小孩安全
编号  5的小孩安全
编号  1的小孩离队了,他携带的密码是  5
编号  4的小孩安全
编号  5的小孩安全
编号  4的小孩安全
编号  5的小孩安全
编号  4的小孩离队了,他携带的密码是  2
最后编号 5 的小孩获胜!
Process returned 23 (0x17)   execution time : 8.506 s
Press any key to continue.

原文:http://www.nowamagic.net/librarys/veda/detail/1867 

posted @ 2012-06-02 11:30  希亚  阅读(491)  评论(0编辑  收藏  举报