uva live 3882 And Then There Was One 约瑟夫环

来源:互联网 发布:淘宝助理是做什么工作 编辑:程序博客网 时间:2024/05/22 00:37
// uva live 3882 And Then There Was One//// 经典约瑟夫环问题。n是规模,k是每次数的人数,m是第一个出列的人。//// 但是暴力用链表做肯定是不行的,因为 1 <= n <= 10000 , 1<= k <= 10000//  1 <= m <= n; 虽然我知道公式是什么,但是我并不会推导,看了几乎一个下午的//  数学推导过程,又弄了几个样例亲自动手实验一下,这样才算是有了一点明悟。//  下面来分享一下自己能力范围的理解过程。// 推导过程。//// 首先,我们要对问题描述改一下,n个人编号为0,1,2,....,n-1,f[n]表示n个人组成// 的约瑟夫环按照规则后最后一个存活的编号。//// 这样之后,首先,我们知道,第一个出列的人的编号(m-1)%n,则我们可以从// 这个人的后面编号设为k= m % n,则这n-1个人的编号依次为k,k+1,....n-// 1,n,1,2,...k-2;// 则重新编号为0,1,2....n-2,那么我们就可以看作是在这n-1规模的子问题的约// 瑟夫环的基础上,求解n规模的约瑟夫环。//// 设n-1规模的子问题的约瑟夫环的解为f[n-1],则n规模约瑟夫环是 // f[n] = (f[n-1] + k) % n;// 证明过程如下:// 原来编号依次为k,k+1,....n-1,n,1,2,...k-2;// 重新编号以后依次为0,1,2,....,n-2;//// f[n] = (f[n-1] + k) % n;(加上k是因为编号要变成n规模里面的编号,不太明白的// 请看上面的序列)// 而 k = m % n;// 则f[n] = (f[n-1] + m) % n;// // 递推公式是f[i] = (f[i-1] + k) % i;// 而f[1] = 0,则最后的结果是f[n]+1(因为f[n]是0,1...n-1编号的,所以要加1)//// 这样,光秃秃的约瑟夫环问题就结束了。。。//// 在这题中,m是开始第一个跳出的人,我们并不需要在一开始的时候从m开始,// 我们依然从 0 开始,只是最后的结果偏移一下就可以,具体偏移多少,慢慢道来//// 首先,我要强调一点,推导都是从0开始的,这一点请大家牢记心中,而约瑟夫环// 的问题特征则是,从不同的位置算起,出列的依次顺序比从0开始的顺序依次顺序// 整体向右平移了几个单位。// n=8,k=5,m=3为例,出列依次为3,8,6,5,7,2,4,1// n=8,k=5,m=1为例,出列依次为5,2,8,7,1,4,6,3// 整体向右偏移了2,(对n取膜的情况下)//// 那么,我们只要确定起点就可以了,因为编号是0,1,2,...n-1,// 而我们是从m(m是1到n)开始算,则起点的偏移就是m-1,而第一个m-1是出队的// 我们算的是0开始数k个才是第一个出队的,所以,必须再减掉k-1个偏移(相当于// 算m-1是第一个出列的,算起点就是减掉k-1个,起点也算一个哟),这样最后的起点// 的偏移就可以算出来了0 + m - 1 - ( k - 1 ) = m - k;// 因为偏移量是相同的,那么终点也是这么多则结果为f[n] + m - k 是最终的结果// 而这个最终的编号是0,1,2...n-1(n-1编号之内)。最后的结果在加上一个1,// 最后结果f[n] + m - k + 1,最后对n取膜,保障在1到n编号就可以了。。。//// 至此,这道题的解析就正式结束了。。。。//// 解题感悟//// 以前做过朴素的约瑟夫环,知道这个公式,但是这道题却是完全不会,只要变一点// 就不会做了,最后狠下心来,几乎这一天都在啃这个公式。最后终于有了一丝理解// //// 这道题目的体悟在于,在推公式的时候,当自己认为是理所当然的时候,请停下来// 问问自己,为什么,在推导这个公式的时候,虽然对于一些人来说很简单,但是对// 于我来说,是挺难的,对于我这蒟蒻来说。所以,在我以为差不多的时候,我停下// 来了,问了自己为什么,发现自己,完全不能回答自己的问题,那么,我就再重新// 的推导,百思不得其解,为什么会是这样。苦思冥想,最后,猛然间,一丝的明悟// 涌上心头,一阵狂喜。哈哈哈哈,这种感觉很奇妙,很充实。//// 最后,还是,继续练吧,路还长着呢,继续走吧#include <algorithm>#include <bitset>#include <cassert>#include <cctype>#include <cfloat>#include <climits>#include <cmath>#include <complex>#include <cstdio>#include <cstdlib>#include <cstring>#include <ctime>#include <deque>#include <functional>#include <iostream>#include <list>#include <map>#include <numeric>#include <queue>#include <set>#include <stack>#include <vector>#define ceil(a,b) (((a)+(b)-1)/(b))#define endl '\n'#define gcd __gcd#define highBit(x) (1ULL<<(63-__builtin_clzll(x)))#define popCount __builtin_popcountlltypedef long long ll;using namespace std;const int MOD = 1000000007;const long double PI = acos(-1.L);template<class T> inline T lcm(const T& a, const T& b) { return a/gcd(a, b)*b; }template<class T> inline T lowBit(const T& x) { return x&-x; }template<class T> inline T maximize(T& a, const T& b) { return a=a<b?b:a; }template<class T> inline T minimize(T& a, const T& b) { return a=a<b?a:b; }const int maxn = 10008;int n,m,k;int f[maxn];void fun(){f[1] = 0;for (int i=2;i<=n;i++)f[i] = (f[i-1] + k) % i;}int main() {//freopen("G:\\Code\\1.txt","r",stdin);while(scanf("%d%d%d",&n,&k,&m)!=EOF){if (!n && !m && !k)break;fun();int ans = (f[n] + m - 1 + 1 - k + 1)%n;if (ans<=0)ans += n;printf("%d\n",ans);}return 0;}

0 0
原创粉丝点击