#include <stdio.h> int josephus(int n, int k) { if (n == 1) return 1; else return (josephus(n - 1, k) + k-1) % n + 1; } int main() { int n = 7, k = 3; // n为总人数,k为报数间隔 printf("The chosen one is %d\n", josephus(n, k)); return 0; }
时间: 2024-03-07 22:54:11 浏览: 15
这是一个经典的约瑟夫问题的解决方案,其中约瑟夫问题是一个著名的数学问题,它的故事可以描述如下:
一群犯人被困在一座监狱里,他们被告知,所有人都必须参与一个游戏,这个游戏的规则是:所有人围成一圈,从某个人开始,每轮从这个人开始顺时针报数,报到第k个人就要出局,直到只剩下一个人为止,这个人将被释放。问这个人应该站在哪个位置,才能保证自己成为最后一个幸存者?
这段代码实现了一个递归函数 `josephus`,它的输入参数有两个:n 表示总人数,k 表示报数间隔。函数的返回值是最后剩下的那个人的编号。
函数中,首先判断如果只有一个人(n==1),那么这个人就是最后的幸存者,直接返回1即可。
否则,递归调用 `josephus(n-1, k)`,表示在 n-1 个人中,每 k 个人出局,最后剩下的人的编号。这个结果加上 k-1,再对 n 取模,再加上 1,就是 n 个人中,每 k 个人出局,最后剩下的人的编号。
在 main 函数中,设置了总人数 n=7,报数间隔 k=3,然后调用 `josephus` 函数求解,最后输出结果。
相关问题
这段代码为什么输出都是1#include <stdio.h> int josephus(int sum, int number){ if (sum=1){ return 0; }else{ return (josephus(sum-1, number)+number+1)%sum; } } int main() { int sum; //总人数 int number; //报数的数字 int code; //剩下最后一个人的编号 while (scanf("%d", &sum) && scanf("%d", &number) == 1){ code=josephus(sum, number); printf("%d\n", code); } }
这段代码输出都是1的原因是因为函数josephus中的判断条件是错误的。在if语句中,应该使用双等号来比较sum和1是否相等,而不是单等号。单等号会把1赋值给sum,导致递归的时候传入的参数不正确,从而得出错误的结果。修改后的代码如下:
```
#include <stdio.h>
int josephus(int sum, int number) {
if (sum == 1) {
return 0;
} else {
return (josephus(sum - 1, number) + number) % sum;
}
}
int main() {
int sum; //总人数
int number; //报数的数字
int code; //剩下最后一个人的编号
while (scanf("%d", &sum) && scanf("%d", &number) == 1) {
code = josephus(sum, number);
printf("%d\n", code);
}
return 0;
}
```
这样修改后,就能得到正确的结果了。
#include<stdio.h> #include<stdlib.h> // #define _CRT_SECURE_NO_WARNINGS typedef struct List{ int data; struct List *next; }list; list *InitList(list L) { L=(list)malloc(sizeof(list)); L->next=L; return L; } list *Findrear(list *l) { list *p; if(l==NULL) p=NULL; else { p=l; while(p->next!=l) p=p->next; } return p; } void Append(list *L,int n) { int i=1; while(i<=n) { if(L->next==L) { L->data=i; } else { list q=(list)malloc(sizeof (list)); list *rear; rear= Findrear(L); q->data=i; q->next=L; rear->next=q; } i++; } } void printfNumber(list *l,int m,int n) { int j=1; while(n>=3) { j++; l=l->next; if(j==m-1) { list *q=l->next; j=1; n--; printf(" %d",q->data); l->next=q->next; free(q); } } printf(" %d",l->data); printf(" %d",l->next->data); } int main() { list *l = NULL; l=InitList(l); int n; int i=1; scanf_s("%d",&n); int m; scanf_s("%d",&m); Append(l,n); printfNumber(l,m,n); return 0; }如何修改这段代码实现约瑟夫环问题
这段代码实现约瑟夫环问题的思路不太正确,需要进行较大的修改。下面是修改后的代码:
```
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int num;
struct Node* next;
} node;
node* createList(int n) {
// 创建含有n个节点的单向循环链表,返回链表头指针
node* head = (node*)malloc(sizeof(node));
head->num = 1;
head->next = NULL;
node* tail = head;
for (int i = 2; i <= n; i++) {
node* p = (node*)malloc(sizeof(node));
p->num = i;
p->next = NULL;
tail->next = p;
tail = p;
}
tail->next = head; // 链接成循环链表
return head;
}
void Josephus(int m, int n) {
// 每次数m个节点,删除第m个节点,直到链表中只剩一个节点
node* head = createList(n);
node* p = head; // p指向当前节点的前一个节点
while (p->next != p) {
for (int i = 1; i < m; i++) {
p = p->next;
}
node* q = p->next; // q指向要删除的节点
printf("%d ", q->num);
p->next = q->next;
free(q);
}
printf("%d\n", p->num);
free(p);
}
int main() {
int n, m;
scanf_s("%d%d", &n, &m);
Josephus(m, n);
return 0;
}
```
修改后的代码中,使用单向循环链表来实现约瑟夫环问题。首先创建含有n个节点的单向循环链表,然后从链表头开始每次数m个节点,删除第m个节点,直到链表中只剩一个节点。在删除节点时,需要先将当前节点的前一个节点p指向要删除的节点的后一个节点,然后释放要删除的节点q的内存。最后输出剩下的节点的编号。