约瑟夫环

1073 约瑟夫环

约瑟夫环的公式为:f(1) = 0;

         f(n) = (f(n-1)+k)%n (n>1)

 

 

推理过程如下:

思路: 直接模拟的话O(n*k)的时间复杂度,按照套路来的话这样的题一般是能找规律的;
我们先将n个人的编号改成0~n-1(别问为什么,套路而已),那么第1次报到号码为k-1的人出列,圈里还剩下n-1个人
我们对比一下出列前后的编号:

出列前: 0, 1, 2, 3, 4, 5, 6, ...k-2, k-1, k... n-1
出列后: n-k+1,..................n-2, , 1... n-k

我们可以发现留下的人编号和留下来之前是一一对应的,那么要是能找到对应关系的话问题就迎刃而解了,不过现在数据太多了不好找
(偶就是这里找错了规律然后只过了样例),我们接着往下想想...
按照前面的规律,第n次报数时只有一个人,我们给他重新编号为0.前面我们也知道了某一轮某个人的编号和上一轮是对应的,最后留下的人此时的编号为0,
那么只要我们由它上溯并找到它在第一轮时的编号答案就出来了啦~
我们用f(x)表示最后留下来那个人在第n-x+1轮中的编号(这样做我们就是由f(1)推f(n),更直观一些,反之由f(n)推f(1)也是可以的),那么f(n)+1就是
最终答案了啦.很显然有f(1)=0(因为此时只剩下一个人了嘛),接下来我们需要找到两轮编号之间的映射关系,这个可以有枚举k和x得到,这里就不写枚举
过程了啦~
最后我们可以得到公式 f(x)=(f(x-1)+k)%x;


来源为:http://www.cnblogs.com/geloutingyu/p/6202200.html
 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 
 5 int main(){
 6     int n,k;
 7     cin >> n >> k;
 8     int f = 0;
 9     for(int i = 2; i <= n; i ++){
10         f = (f+k)%i;
11     }
12     cout << f+1 << endl;
13     return 0;
14 }

 

posted @ 2017-07-02 17:28  starry_sky  阅读(200)  评论(0编辑  收藏  举报