约瑟夫问题
来源:互联网 发布: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;}
- 约瑟夫问题、约瑟夫环
- 约瑟夫问题
- 约瑟夫问题
- 约瑟夫问题
- 约瑟夫问题
- 约瑟夫问题
- 约瑟夫问题
- 约瑟夫问题
- 约瑟夫问题
- 约瑟夫问题
- 约瑟夫问题
- 约瑟夫问题
- 约瑟夫问题
- 约瑟夫问题
- 约瑟夫问题
- 约瑟夫问题
- 约瑟夫问题
- 约瑟夫问题
- Codeforces CROC problem C
- Oracle:外键关联导致数据无法删除
- 利用NFS服务挂载NFS根文件系统
- Android通过JNI调用驱动程序(完全解析实例)
- 使用Gnu gprof进行Linux平台下的程序分析
- 约瑟夫问题
- 贪心之hdu1045
- WCF足迹10:异常2
- Python3中bytes和HexStr之间的转换
- 基于LGPL开源项目 Log4cpp安装与使用
- keyCode 对照表
- java.sql.SQLException: ORA-08102
- 浏览器如何工作
- 图表rgraph