一、约瑟夫问题
一、約瑟夫問題
文章目錄
- 一、約瑟夫問題
- 題目描述
- 解題思路
- 上機代碼:
- 解法一:數組模擬
- 解法二:鏈表模擬
題目描述
約瑟夫問題是一個經典的問題(大一我們講過)。這個問題可以用數組,也可以用鏈表。作為復習,大家可以試試你自己的算法。
已知n個人(不妨分別以編號1,2,3,…,n 代表 )圍坐在一張圓桌周圍,從編號為 k 的人開始,從1開始順時針報數1, 2, 3, …,順時針數到m 的那個人,出列并輸出。然后從出列的下一個人開始,從1開始繼續順時針報數,數到m的那個人,出列并輸出,…依此重復下去,直到圓桌周圍的人全部出列。
- 輸入:n, k, m
- 輸出:按照出列的順序依次輸出出列人的編號,編號中間相隔一個空格,每10個編號為一行。
非法輸入的對應輸出如下
a)
輸入:n、k、m任一個小于1
輸出:n,m,k must bigger than 0.
b)
輸入:k>n
輸出:k should not bigger than n.
| 測試用例 1 | 9,3,2 | 4 6 8 1 3 7 2 9 5 | 1秒 | 64M | 0 |
| 測試用例 2 | 10,12,3 | k should not bigger than n. | 1秒 | 64M | 0 |
解題思路
這是一個典型的模擬題,我們可以用兩種方式來實現:數組或者鏈表。
-
采用數組的方式,初始化一個元素值都為0的數組,每次選中出局元素后將其值置為-1,以后遇到-1則跳過,非-1則計數。直到所有元素全部出局,即數組可用長度為0時終止
-
采用鏈表的方式,初始化一個長度為n的循壞鏈表,每次選中出局結點后將其刪除,將余下結點連接,繼續計數。直到所有結點均被刪除為止
上機代碼:
解法一:數組模擬
#include <stdio.h> #include <stdlib.h> #include <string.h> #define LineFeed 10 /*解法一,數組模擬 */ int main() {/*n,k,m分別對應n個人,從編號k開始,每次數m個*/int n=0, k=0, m=0;scanf("%d,%d,%d", &n, &k, &m);/*非法輸入的對應輸出*/if(n<1 || k<1 || m<1){printf("k should not bigger than n.");return 0;}if (k>n){printf("k should not bigger than n.");return 0;}/*正常輸入,用數組模擬約瑟夫環*///初始化int a[10010];memset(a,0,sizeof(a));//數組長度,換行標志,位移記錄int len=n, flag=0, ans=k;while(len){//位移指針,計數器int i=ans-1, count=0;while(i++){//保證指針循環索引if(i>n){i=i%n;}//-1即已經出局,跳過if (a[i]==-1){continue;}count++;if(count==m)//到達m步{a[i]=-1;len--;flag++;ans=i+1;//記錄當前位移if(flag==LineFeed)//累計輸出10個元素,換行{printf("%d\n", i);flag=0;}else if(len>0){printf("%d ", i);}else//最后一個元素換行{printf("%d\n", i);}break;}}}return 0; }解法二:鏈表模擬
#include <stdio.h> #include <stdlib.h> #define LineFeed 10 /*解法二,鏈表模擬 */ typedef struct node {int data;struct node *next; }NODE, *PNODE;int main() {/*n,k,m分別對應n個人,從編號k開始,每次數m個*/int n=0, k=0, m=0;int flag=0;//換行標志scanf("%d,%d,%d", &n, &k, &m);/*非法輸入的對應輸出*/if(n<1 || k<1 || m<1){printf("k should not bigger than n.");return 0;}if (k>n){printf("k should not bigger than n.");return 0;}/*正常輸入,用循環鏈表模擬約瑟夫環*///初始化頭結點PNODE head,p,q;head=(PNODE)malloc(sizeof(NODE));head->data=-1;head->next=head;//頭插法建立鏈表for (int i = n; i > 0; i--){p=(PNODE)malloc(sizeof(NODE));p->data=i;p->next=head->next;head->next=p;}//構建循環while(p->next!=head){p=p->next;}p->next=head->next;free(head);//找到計數的初始位置的前一個結點for (int i = 0; i < k-1; i++){p=p->next;}//開始循環剔除結點for (int i = 1; i <= n; i++){//走m-1步,下一個就是要剔除的結點for (int j = 0; j < m-1; j++){p=p->next;}//鎖定要剔除的結點q=p->next;//調整輸出flag++;if(flag==LineFeed)//累計輸出10個元素,換行{printf("%d\n", q->data);flag=0;}else if(i==n)//最后一個結點,換行{printf("%d\n", q->data);}else{printf("%d ", q->data);}//剔除該結點p->next=q->next;free(q);}return 0; }總結