POJ——3517

  题目链接:http://poj.org/problem?id=3517

  其实基本就是约瑟夫环问题,最终accepted的answer是看过相关资料才写出来的:

  无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂 度高达O(nm),

当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。

为了讨论方便,先把问题稍微改变一下,并不影响原意:

问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。

我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始):

k k+1 k+2 ... n-2, n-1, 0, 1, 2, ... k-2 并且从k开始报0。 现在我们把他们的编号做一下转换:

k --> 0

k+1 --> 1

k+2 --> 2

... ...

k-2 --> n-2

k-1 --> n-1

  变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:

例如x是最终的胜利者,那么根 据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!

变回去的公式很简单,相信大家都可以推出来:

x=(x+k)%n

如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。(n-2)个人的解呢?当然是先求(n-3)的 情况 ---- 这显然就是一个倒推问题!

代码:Accepted:

 1 #include<iostream>
 2 #define MAX 100
 3 
 4 using namespace std;
 5 
 6 int main(){
 7     int n = 1, k = 1, m = 1, cnt =0;
 8     int rel[MAX] = { 0 };
 9     while((n!=0) && (k!=0) && (m!=0))
10     {
11         cin >> n >> k >> m;
12          if((n!=0) && (k!=0) && (m!=0))
13         {
14             int f=0;
15             for(int i=2;i<n;i++)
16                 f=(f+k)%i;
17             f=(f+m)%n;
18             rel[cnt] = f+1;
19             cnt++;
20         }
21     }
22     for(int i = 0;i < cnt;i++)
23     {
24         cout << rel[i] << endl;
25     }
26     return 0;
27 }

  我用链表写的,总超时,后面我对其进行了很多优化,也通不过,我怀疑只能通过数学解法做,也列出来吧

  链表的约瑟夫问题太有名了,以至于我神马都没想,就直接用链表做了

 1 #include <iostream>
 2 #define MAX 100
 3 using namespace std;
 4 
 5 typedef struct node
 6 {
 7     int num;
 8     node* nxt;
 9 }node;
10 typedef node* Lst;
11 
12 int Final(int n, int k, int m);
13 
14 int main()
15 {
16     int n = 1, k = 1, m = 1, cnt =0;
17     int rel[MAX] = { 0 };
18     while((n!=0) && (k!=0) && (m!=0))
19     {
20         cin >> n >> k >> m;
21         if((n!=0) && (k!=0) && (m!=0))
22         {
23             rel[cnt] = Final(n,k,m);
24             cnt++;
25         }
26 
27     }
28 
29     for(int i = 0;i < cnt;i++)
30     {
31         cout << rel[i] << endl;
32     }
33 
34      /*for(int i = 0; i < 2*n;i++)
35     {
36         cout << head->num<<endl;
37         head = head->nxt;
38     }*/
39 
40     return 0;
41 }
42 int Final(int n, int k, int m)
43 {
44     Lst L, head, tmp;
45     L = new node;
46     L->nxt = L;
47     head = L;
48     L->num = 1;
49 
50     for(int i = 1; i < n;i++)
51     {
52         //Insert(L, i+1)
53         tmp = new node;
54         tmp->num = i+1;
55         head->nxt = tmp;
56         tmp->nxt = L;
57         head = tmp;
58         //cout << head->num << " \t";
59     }
60     int stonecnt = n;
61     head = L;
62     for(int i = 0;i < (m-1)%n; i++)
63     {
64         tmp =head;
65         head = head->nxt;
66     }
67     stonecnt--;
68     Lst del = head;
69     head = head->nxt;
70     tmp->nxt = head;
71     delete del;
72     while(stonecnt > 1)
73     {
74         for(int i = 0;i < (k-1)%stonecnt; i++)
75         {
76             tmp =head;
77             head = head->nxt;
78         }
79         stonecnt--;
80         del = head;
81         head = head->nxt;
82         tmp->nxt = head;
83         delete del;
84     }
85     int rel = head->num;
86     delete head;
87     return rel;
88 }
原文地址:https://www.cnblogs.com/moondark/p/2587169.html