什么是約瑟夫問題?
約瑟夫問題:n個人圍成一圈,初始編號從1~n排列,從約定編號為x的人開始報數,數到第m個人出圈,接着又從1開始報數,報到第m個數的人又退出圈,以此類推,最后圈內只剩下一個人,這個人就是贏家,求出贏家的編號。
是不是有點點復雜,其實該問題歸結為模擬類型的算法題,根據題目要求模擬即可。
環形鏈表
1、先創建一個環形鏈表來存放元素:
2、然后一邊遍歷鏈表一遍刪除,直到鏈表只剩下一個節點,我這里就不全部演示了
那么,通過前面對環形鏈表的了解,以你的智慧應該會輕松解決簡單的約瑟夫問題了。
不妨我們加大難度,設有編號為1,2,3,...,n(n>0)個人按順時針順序圍坐一圈,沒人手持一個隨機產生的密碼(正整數)。現從第k個人開始順時針的方向以1開始報數,報數的上限第一個人持有的密碼m,報到m的人出列,然后將出列的人所持有的密碼作為新的m值,從下一個人開始重新從1開始報數,如此下去,直到最后一個人出列為止,要求設計一個程序模擬此過程,並輸出他們的列編號序列
問題分析
很顯然這是一個線性結構,可以用線性表來表示。進行的主要操作是報數、出列,這個相當於對線性表進行刪除操作,因此宜用用鏈表存儲結構,每個節點表示一個人。n個人圍城一圈循環報數,則利用單循環鏈表存儲結構更容易解決問題。
因此,
第一步需要創建單循環鏈表,每個節點存儲節點序號和密碼,密碼隨機生成(1-10)
第二步實現循環刪除操作,將密碼作為每次循環的步長(這里指的是距離)
第三步實現打印操作(跟隨第二步操作)
程序設計
/*單循環鏈表的存儲結構*/
typedef struct
{
int num;//序號
int pwd;//密碼
struct Joseph *next;
}Joseph;
輸入設計
在一行中輸入總人數和第幾個人開始報數
輸入設計
首先輸出每個人的編號以及持有的密碼,其次輸出出列的編號次序,最后輸出幸存者。
基本操作
創建鏈表:Joseph* creatList(Joseph* head,int n);
輸出每個人的序號以及密碼:void printList(Joseph* head,int n);
初始從第k個人開始報數,輸出出列次序:void outList(Joseph *head,int k);
程序代碼
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <malloc.h>
/*約瑟夫環問題
*單循環鏈表的創建
*打印單循環鏈表
*循環淘汰m,最后留下幸存者
*/
typedef struct
{
int num;
int pwd;
struct Joseph *next;
}Joseph;
Joseph* creatList(Joseph* head,int n)
{
int i;
Joseph *p,*q;
q = head;
q->num = 1;
q->pwd = rand()%10+1;
for(i = 2;i<=n;i++) //尾插法
{
p = (Joseph*)malloc(sizeof(Joseph));
p->num = i;
p->pwd = rand()%10+1;
q->next = p;
q = p;
}
p->next = head;
}
void printList(Joseph* head,int n)
{
int i;
Joseph *list;
list = head;
for(i = 0;i<n;i++)
{
printf("第%d位的密碼是%d\n",list->num,list->pwd);
list = list->next;
}
}
void outList(Joseph *head,int k)
{
Joseph *p,*q;
q = (Joseph*)malloc(sizeof(Joseph));
p = head;
int m;
for(int i = 1;i<k;i++) //找第k個節點,作為開始
{
q = p;
p = p->next;
}
m = head->pwd; //第k個節點的密碼作為步長(這里指的是距離)
while(p!=q) //當留下最后一個節點時p = q
{
for(int i = 1;i<m;i++)
{
q = p;
p = p->next;
}
m = p->pwd;
printf("%d ",p->num);
q->next = p->next;
free(p);
p = q->next;
}
printf("\n幸存者:%d",q->num);
free(p);
}
int main()
{
Joseph *joseph;
joseph = (Joseph*)malloc(sizeof(Joseph));
int n;
printf("輸入總人數:");
scanf("%d",&n);
creatList(joseph,n);
printList(joseph,n);
int k;
printf("輸入從第幾個人開始報數:");
scanf("%d",&k);
outList(joseph,k);
return 0;
}
約瑟夫問題:一行代碼就解決了 ————轉載