约瑟夫问题

来源:互联网 发布:qq群做淘宝客如何赚钱 编辑:程序博客网 时间:2024/06/05 09:33

原文地址:http://blog.fishc.com/1959.html

约瑟夫问题

 

据说著名犹太历史学家 Josephus有过以下的故事:

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

 

理论付诸实践

 

小甲鱼:理论为什么能够付诸实践?

热心鱼油:你TMD在说啥*&(*%@……!

小甲鱼:我的意思是约瑟夫问题跟我们讲的循环链表有啥关系?

某女鱼油:它们都带套!

小甲鱼:真聪明,亲一个^_^

小甲鱼:对的,约瑟夫问题里边41个人是围成一个圆圈,我们的循环链表也是一个圆圈,所以可以模拟并让计算机运行告诉我们结果!

 

问题:用循环链表模拟约瑟夫问题,把41个人自杀的顺序编号输出。

//n个人围圈报数,报m出列,最后剩下的是几号?#include <stdio.h>#include <stdlib.h>typedef struct node{int data;struct node *next;}node;node *create(int n){node *p = NULL, *head;head = (node*)malloc(sizeof (node ));p = head;node *s;int i = 1;if( 0 != n ){while( i <= n ){s = (node *)malloc(sizeof (node));s->data = i++;    // 为循环链表初始化,第一个结点为1,第二个结点为2。p->next = s;p = s;}s->next = head->next;}free(head);return s->next ;}int main(){int n = 41;int m = 3;int i;node *p = create(n);node *temp;m %= n;   // m在这里是等于2while (p != p->next ){for (i = 1; i < m-1; i++){p = p->next ;}printf("%d->", p->next->data );temp = p->next ;//删除第m个节点p->next = temp->next ;free(temp);p = p->next ;}printf("%d\n", p->data );return 0;}

另一种实现:

#include "stdafx.h"#include <stdio.h>#include <stdlib.h>typedef struct Node{int m_num;Node *next;}node;void initList(int num,node **pHead){if((*pHead)==NULL)(*pHead)=(node*)malloc(sizeof(node));if(!(*pHead))exit(0);(*pHead)->m_num=1;(*pHead)->next=(*pHead);node *cur=(*pHead);for(int i=2;i<=num;i++){node *tmp=(node*)malloc(sizeof(node));if(!tmp)exit(0);tmp->next=*pHead;tmp->m_num=i;cur->next=tmp;cur=tmp;}}void printNum(node* pHead){node *p1=pHead;node *p2=NULL;node *p3=NULL;while(1){p2=p1->next;p3=p2->next;if(p1==p3)break;printf("%d,",p3->m_num);p2->next=p3->next;p1=p3->next;free(p3);}pHead=p1;printf("\n活下来的人:%d,%d\n",pHead->m_num,pHead->next->m_num);}int _tmain(int argc, _TCHAR* argv[]){node *pHead=NULL;initList(41,&pHead);printNum(pHead);system("pause");return 0;}


提高挑战难度:

编号为1~N的N个人按顺时针方向围坐一圈,每人持有一个密码(正整数,可以自由输入),开始人选一个正整数作为报数上限值M,从第一个人按顺时针方向自1开始顺序报数,报道M时停止报数。报M的人出列,将他的密码作为新的M值,从他顺时针方向上的下一个人开始从1报数,如此下去,直至所有人全部出列为止。

#include <stdio.h>#include <stdlib.h>#define MAX_NODE_NUM 100#define TRUE 1U#define FALSE 0Utypedef struct NodeType{    int id;    int cipher;    struct NodeType *next;} NodeType;/* 创建单向循环链表 */static void CreaList(NodeType **, const int);/* 运行"约瑟夫环"问题 */static void StatGame(NodeType **, int);/* 打印循环链表 */static void PrntList(const NodeType *);/* 得到一个结点 */static NodeType *GetNode(const int, const int);/* 测试链表是否为空, 空为TRUE,非空为FALSE */static unsigned EmptyList(const NodeType *);int main(void){    int n, m;    NodeType *pHead = NULL;    while (1)    {        printf("请输入人数n(最多%d个): ", MAX_NODE_NUM);        scanf("%d", &n);        printf("和初始密码m: ");        scanf("%d", &m);        if (n > MAX_NODE_NUM)        {            printf("人数太多,请重新输入!\n");            continue;        }        else            break;    }    CreaList(&pHead, n);    printf("\n------------ 循环链表原始打印 -------------\n");    PrntList(pHead);    printf("\n-------------删除出队情况打印 -------------\n");    StatGame(&pHead, m);}static void CreaList(NodeType **ppHead, const int n){    int i, iCipher;    NodeType *pNew, *pCur;    for (i = 1; i <= n; i++)    {        printf("输入第%d个人的密码: ", i);        scanf("%d", &iCipher);        pNew = GetNode(i, iCipher);        if (*ppHead == NULL)        {            *ppHead = pCur = pNew;            pCur->next = *ppHead;        }        else        {            pNew->next = pCur->next;            pCur->next = pNew;            pCur = pNew;        }    }    printf("完成单向循环链表的创建!\n");}static void StatGame(NodeType **ppHead, int iCipher){    int iCounter, iFlag = 1;    NodeType *pPrv, *pCur, *pDel;    pPrv = pCur = *ppHead;    /* 将pPrv初始为指向尾结点,为删除作好准备 */    while (pPrv->next != *ppHead)        pPrv = pPrv->next;    while (iFlag)    {        for (iCounter = 1; iCounter < iCipher; iCounter++)        {            pPrv = pCur;            pCur = pCur->next;        }        if (pPrv == pCur)            iFlag = 0;        pDel = pCur; /* 删除pCur指向的结点,即有人出列 */        pPrv->next = pCur->next;        pCur = pCur->next;        iCipher = pDel->cipher;        printf("第%d个人出列, 密码: %d\n", pDel->id, pDel->cipher);        free(pDel);    }    *ppHead = NULL;    getchar();}static void PrntList(const NodeType *pHead){    const NodeType *pCur = pHead;    if (EmptyList(pHead))        return;    do    {        printf("第%d个人, 密码: %d\n", pCur->id, pCur->cipher);        pCur = pCur->next;    }    while (pCur != pHead);    getchar();}static NodeType *GetNode(const int iId, const int iCipher){    NodeType *pNew;    pNew = (NodeType *)malloc(sizeof(NodeType));    if(!pNew)    {        printf("Error, the memory is not enough!\n");        exit(-1);    }    pNew->id = iId;    pNew->cipher = iCipher;    pNew->next = NULL;    return pNew;}static unsigned EmptyList(const NodeType *pHead){    if(!pHead)    {        printf("The list is empty!\n");        return TRUE;    }    return FALSE;}


原创粉丝点击