Problem Description
The Joseph's problem is notoriously known. For those who are not familiar with the original problem: from among n people, numbered 1, 2, . . ., n, standing in circle every mth is going to be executed and only the life of the last remaining person will be saved. Joseph was smart enough to choose the position of the last remaining person, thus saving his life to give us the message about the incident. For example when n = 6 and m = 5 then the people will be executed in the order 5, 4, 6, 2, 3 and 1 will be saved.
Suppose that there are k good guys and k bad guys. In the circle the first k are good guys and the last k bad guys. You have to determine such minimal m that all the bad guys will be executed before the first good guy.
Suppose that there are k good guys and k bad guys. In the circle the first k are good guys and the last k bad guys. You have to determine such minimal m that all the bad guys will be executed before the first good guy.
Input
The input file consists of separate lines containing k. The last line in the input file contains 0. You can suppose that 0 < k < 14.
Output
The output file will consist of separate lines containing m corresponding to k in the input file.
Sample Input
3
4
0
Sample Output
5
30
题意:给出一个k,代表有K个好人与K个坏人,其中前K个是好人,后K个是坏人,根据约瑟夫环游戏的原理,在坏人都出局而好人没有一个都没有出局的情况下,m最小是多大
#include<stdio.h> #include<malloc.h> #include<string.h> int vist[30]; typedef struct list { int data; struct list *next; }Lnode,*LinList; void creat_L(LinList *L) { (*L)=(LinList)malloc(sizeof(Lnode)); (*L)->data=0; (*L)->next=(*L);//形成环 } int DeleteNode(LinList L,int k,int n)//n是走的步数,k是有多少个好人和坏人 { int j,i=0,badk=0,mod; LinList q=L; while(i<k)//i是代表有i个坏人被处决 { q=q->next; j=1;//j=1是从当前位置开始计数,看下面的代码 while(vist[q->data]||q->data==0)//跳过己经处决的,vist为0时,表示这人还活着 { q=q->next; } mod=n%(2*k-i);//(2*k-i)代表活着的人数,mod就等于走了很多圈以后余下的步数少于活着的人数 if(mod==0)//代表从当前位置走了n步后又最后会回到当前位置,那么就等于活着的人数 mod=2*k-i; while (j<mod)//开始走 { q=q->next; if(vist[q->data]==0&&q->data!=0)//为了跳过处决了的,活着才能+1,算是一步 j++; } if(q->data<=k)//代表处决的是好人,不满足只处决坏人,不用往下走了,跳出循环 break; if(q->data>k)//大于k的说明处决的是坏人,那么计数加一个 badk++; vist[q->data]=1;//代表处决了 i++; //下一次 //printf("%d ",q->data); } return badk;//反回处决坏人的人数 } void Crea_list(LinList L,int n)//创建一个以n个人的圈 { int i; LinList q=L,p; for(i=n;i>=1;i--) { p=(LinList)malloc(sizeof(Lnode)); p->data=i; p->next=q->next; q->next=p; } } int main() { int i,k,m,j,t,a[16]; LinList L,q; for(j=1;j<14;j++)//打表 { creat_L(&L); Crea_list(L,2*j); q=L; if(j<=9) for(m=j+1;;m++)//表法要直的步数 { memset(vist,0,sizeof(vist)); t=DeleteNode(L,j,m); if(t==j)//表法以当前的步数走,处决的坏个等于坏人总数,就跳出来 break; } else { m=90000; for(;;m++) { memset(vist,0,sizeof(vist)); t=DeleteNode(L,j,m); if(t==j) break; } } a[j]=m; } while(scanf("%d",&k)>0&&k) { printf("%d\n",a[k]); } } /* 1 2 2 7 3 5 4 30 5 169 6 441 7 1872 8 7632 9 1740 10 93313 11 459901 */