约瑟夫问题

来源:互联网 发布:冷钢刀怎么样啊 知乎 编辑:程序博客网 时间:2024/06/12 01:24

约瑟夫问题是经典的循环链表。
1)内容: 约瑟夫(Joseph)问题的一种描述是:编号为1,2,…, n 的n 个人按顺 时针方向围坐一圈, 每人持有一个密码(正整数)。一开始选任一个正整数作为报数上限值m, 从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将它的密码作为新的m值,再从下个人开始新一轮报数,如此反复,直到剩下最后一人则为获胜者。试设计一个程序求出出列顺序。
2)要求: 利用单向循环链表存储结构模拟此过程, 按照出列的顺序印出各人的编号。
3) 测试数据: n=7,7 个人的密码依次为:3,1,7,2,4,8,4 。m的初值为20,则正确的出列顺序应为6,1,4,7,2,3,5

#include <stdio.h>#include <stdlib.h>// 结构体的定义typedef struct Person {    int order;    int password;    struct Person * next;} Person;Person * pHead = NULL;  // 链表的第一个节点 Person * pTail = NULL;  // 链表的尾部    Person * per = NULL;    // 用于遍历 int n, m;// 下面是函数的声明void Create();  // 创建一个链表void Joseph(int m); // 约瑟夫问题的执行函数int main(void){    // n为总人数, m为初始密码    scanf("%d %d", &n, &m);    Create(); // 创建链表    per = pHead;  // 将用于遍历的节点指向头节点,因为下面的这个函数使用递归写的    Joseph(n);    return 0;} void Create() {    // 定义一个为节点    Person * tail;    for (int i = 0; i < n; i++) {        Person * person;        person = (Person *) malloc(sizeof(Person));        person->order = i + 1;        scanf("%d", &person->password);        if (pHead == NULL) {            pHead = person;        } else {            tail->next = person;        }        tail = person;    }    // 因为是循环链表,所以必须将尾与头连接起来    tail->next = pHead;    // 将函数中的尾节点赋给全局变量中的尾节点    // 这个在后面有用    pTail = tail;}/** 因为最后最后每一个人都会报数(最后一个报数的为获胜者)* 一次递归出列一个人,所以要需要递归n次*/void Joseph(int number) {    // 当number为0时结束递归    if (number == 0) {        return;    }    // 用于报数,第一个人报1所以初始值为1    int count = 1;    // p用于记录删除的节点    Person * p = NULL;    // 前面记录的为指针的用处就在这里    // 当m=1时,第一个人出列,所以就不用进行下面的循环    // 但是当m不等于1时,找到那个要出列的节点    while (count != m) {        per = per->next;        pTail = pTail->next;        count++;    }    // p为要删除的节点    p = per;    // 重置m    m = p->password;    // 从链表中删除p    pTail->next = per->next;    // 下面的是输出出列人的编号    // 因为有些ACM要求,用空格间隔,所以最后一个不能有空格    if(number == 1)        printf("%d", p->order);    else        printf("%d ", p->order);    per = per->next;    // 释放p    free(p);    // 进行下一个递归    Joseph(number - 1); }

约瑟夫排列问题

对于给定的1,2,3,…,n中的k个数,Josephus想知道是否存在一个正整数m(m≤n),使得Josephus(n,m)排列的最后k个数恰好为事先指定的k个数。例如当n为7,k为4,指定排列的最后k个数为7,5,1,4时;由于(7,3)Josephus排列为3,6,2,7,5,1,4;所以求得m值为3。

这个约瑟夫排列问题,每个人都没有密码,只有一个初始值,当报到这个人时出列。要求找一个满足题目要求的初始值m。

#include <stdio.h>#include <stdlib.h>typedef struct Person {    int order;    struct Person * next;} Person;Person * pHead = NULL;  // 链表的第一个节点 Person * pFront = NULL;Person * per = NULL;int n, m;int b[100], k;// 函数void Create(); void Joseph(int number, int m);int main(void){    scanf("%d %d", &n, &m);    int i;    int a[n];    for (i = n - m ; i < n; i++) {        scanf("%d", &a[i]);    }    for (i = 1; i <= n; i++) {        pHead = NULL;        pFront = NULL;         k = 0;        int flag = 1;        Create();        per = pHead;        Joseph(n, i);        for (int j = n - m; j < n; j++) {            if (a[j] != b[j]) {                flag = 0;            }        }        if (flag == 1) {            printf("%d", i);            return 0;        }//      printf("\n");    }    printf("0");    return 0;} void Create() {    Person * tail;    for (int i = 0; i < n; i++) {        Person * person;        person = (Person *) malloc(sizeof(Person));        person->order = i + 1;        if (pHead == NULL) {            pHead = person;        } else {            tail->next = person;        }        tail = person;    }    tail->next = pHead;    pFront = tail;}void Joseph(int number, int m) {    if (number == 0) {        return;    }    int count = 1;    Person * p = NULL;    while (count != m) {        per = per->next;        pFront = pFront->next;        count++;    }    p = per;    pFront->next = per->next;    if(number == 1) {        b[k++] = p->order;//      printf("%d", p->order);    }    else {//      printf("%d ", p->order);        b[k++] = p->order;    }    per = per->next;    free(p);    Joseph(number - 1, m); }
0 0
原创粉丝点击