http://acm.hdu.edu.cn/showproblem.php?pid=2925
我嘞个深深地去啊,上次做线段树一直理解不了约瑟夫环,做了一道还是感觉没吃透,这次终于搞定了。。
参考博客:点击打开链接
刚开始一直看不懂,好好看作者的演示图,注意x和x'的含义,还有f[i]是最后胜利者的编号,所以第一个人的f[i]的编号为0,因为怎么数都不可能把离起点最近的人踢掉啊!!
一旦递推公式出来,一切都好办了!!
f[i] = (f[i-1]+k)%i
不过注意上面处理的环是从0~n-1的,踢的数也是第k-1个,所以最后记得加1变回原来的1-n!
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
const int N = 200010;
const int INF = 1e8;
int main()
{
// freopen("in.txt", "r", stdin);
int n, d;
while(~scanf("%d%d", &n, &d))
{
if(n == 0 && d == 0) break;
int ans = 0;
for(int i = 2; i <= n; i ++)
ans = (ans+d)%i;
printf("%d %d %d\n", n, d, ans+1);
}
return 0;
}
http://poj.org/problem?id=3517
poj的这个题是上一道加强了下,规定起点为m。处理方法就是减掉最后一层递归专门用来处理这个起点,处理方法一样。
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
const int N = 200010;
const int INF = 1e8;
int main()
{
// freopen("in.txt", "r", stdin);
int n, k, m;
while(~scanf("%d%d%d", &n, &k, &m))
{
if(n == 0 && k == 0 && m == 0) break;
int ans = 0;
for(int i = 2; i < n; i ++)
ans = (ans+k)%i;
ans = (ans+m)%n;
printf("%d\n", ans+1);
}
return 0;
}