POJ3750: 小孩报数问题+一道经典约瑟夫问题(猴子选大王)

又一次因为一个小错误,POJ上Wrong Answer了无数次。。。。。

在差不多要放弃的时候,发现了这个猥琐的不能再猥琐的bug,改完了提交就AC了,简直无语。。。。

本题wo采用模拟方法:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 struct child{
 6     char name[16];
 7     int id;
 8     //child(string, int);
 9 }cd[100];
10 void init(int n){
11     char s[16];
12     for(int i=1;i<=n;i++){
13         scanf("%s",cd[i].name);
14         cd[i].id=0;
15     }
16 }
17 int main(){
18     int n,w,s; char c;
19     scanf("%d",&n);
20     init(n);
21     scanf("%d%c%d",&w,&c,&s);
22     cd[w].id=1;
23     int pt=w;
24     int kill=0;
25     while(true){
26         int step=s%(n-kill)-1;
27         if(step<=0) step=step+n-kill;
28         /*
29             这里的取模运算是考虑到s值可能非常大,如果这样的话,模拟报数过程1。。。。s将会非常
30             耗时间。
31             至于为什么这么取模,自己算一算就明白了。 
32         */
33         for(int i=1;i<=step;i++){
34                 int ptr=pt%n+1;
35                 while(cd[ptr].id==-1){//要跳过已经被kill的元素 
36                     ptr=ptr%n+1;
37                 }
38                 cd[ptr].id=cd[pt].id+1;
39                 pt=ptr;
40         }//这里的pt指向的就是我们要删除的元素 
41         cd[pt].id=-1;//将id赋值为-1,相当于删除动作 
42         printf("%s
",cd[pt].name);
43         kill++;
44         if(kill==n) break; //已经清空,跳出循环 
45         int ptr=pt%n+1;
46         while(cd[ptr].id==-1){
47                     ptr=ptr%n+1;
48         }
49         cd[ptr].id=1;
50         pt=ptr;
51             
52     }
53     //system("pause");
54     return 0;
55 }
View Code

还有可以用双向循环链表来模拟:

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 using namespace std;
 5 struct node{
 6     int id;
 7     node *next,*pre;
 8     node();
 9     node(int);
10 };
11 node *head;
12 char name[101][20];
13 node::node(int value){
14     id=value;
15     next=pre=NULL;
16 }
17 void build(int n){
18     head=new node(1);
19     head->next=head->pre=head;
20     if(n==1) return;
21     node *p=head;
22     for(int i=2;i<=n;i++){
23         node *a=new node(i);
24         p->next=a;
25         a->pre=p;
26         p=a;        
27     }
28     p->next=head;
29     head->pre=p;
30 }
31 void print(){
32     node *p=head;
33     printf("%d ",p->id);
34     p=p->next;
35     while(p!=head){
36         printf("%d ",p->id);
37         p=p->next;
38     }
39     printf("
");
40 }
41 void joseph(int s,int k){
42     node *p=head;
43     s--;
44     while(s--) p=p->next;
45     while(p->next!=p){
46         for(int i=1;i<=k-1;i++) p=p->next;
47         printf("%s
",name[p->id]);
48         node *front=p->pre;
49         node *rear=p->next;
50         p=rear;
51         front->next=rear;
52         rear->pre=front;        
53     }
54     printf("%s
",name[p->id]);
55 }
56 int main(){
57     int n; char c;
58     scanf("%d",&n);
59         build(n);
60         //print();
61         for(int i=1;i<=n;i++){
62             scanf("%s",name[i]);
63         }
64         int s,k;
65         scanf("%d%c%d",&s,&c,&k);
66         joseph(s,k);
67 }
View Code

猴子选大王问题: 

题目描述约瑟夫问题:有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退出圈外,剩下的猴子再接着从1开始报数。就这样,直到圈内只剩下一只猴子时,这个猴子就是猴王,编程求输入n,m后,输出最后猴王的编号。

输入每行是用空格分开的两个整数,第一个是 n, 第二个是 m ( 0 < m,n <=300)。最后一行是:

0 0

输出对于每行输入数据(最后一行除外),输出数据也是一行,即最后猴王的编号
样例输入

6 2
12 4
8 3
0 0

样例输出

5
1
7
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 struct child{
 6     int name;
 7     int id;
 8     //child(string, int);
 9 }cd[100];
10 void init(int n){
11     for(int i=1;i<=n;i++){
12         cd[i].name=i;
13         cd[i].id=0;
14     }
15 }
16 void solve(int n,int s){
17     init(n);
18     cd[1].id=1;
19     int pt=1;
20     int kill=0;
21     while(true){
22         int step=s%(n-kill)-1;
23         if(step<=0) step=step+n-kill;
24         /*
25             这里的取模运算是考虑到s值可能非常大,如果这样的话,模拟报数过程1。。。。s将会非常
26             耗时间。
27             至于为什么这么取模,自己算一算就明白了。 
28         */
29         for(int i=1;i<=step;i++){
30                 int ptr=pt%n+1;
31                 while(cd[ptr].id==-1){//要跳过已经被kill的元素 
32                     ptr=ptr%n+1;
33                 }
34                 cd[ptr].id=cd[pt].id+1;
35                 pt=ptr;
36         }//这里的pt指向的就是我们要删除的元素 
37         cd[pt].id=-1;//将id赋值为-1,相当于删除动作 
38         kill++;
39         if(kill==n){
40             printf("%d
",cd[pt].name); break; //已经清空,跳出循环 
41         }
42         int ptr=pt%n+1;
43         while(cd[ptr].id==-1){
44                     ptr=ptr%n+1;
45         }
46         cd[ptr].id=1;
47         pt=ptr;
48             
49     }
50 }
51 int main(){
52          int n,s;
53         while(scanf("%d%d",&n,&s)!=EOF&&n&&s){
54             solve(n,s);
55         }
56         return 0;    
57 }
View Code

 

 
原文地址:https://www.cnblogs.com/fu11211129/p/4194343.html