HDU 5643:King's Game 约瑟夫问题

来源:互联网 发布:c语言中mod函数 编辑:程序博客网 时间:2024/05/18 21:09

King's Game

 
 Accepts: 249
 
 Submissions: 671
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
问题描述
为了铭记历史,国王准备在阅兵的间隙玩约瑟夫游戏。它召来了 n(1\le n\le 5000)n(1n5000) 个士兵,逆时针围成一个圈,依次标号 1, 2, 3 ... n1,2,3...n。第一轮第一个人从 11 开始报数,报到 11 就停止且报到 11 的这个人出局。第二轮从上一轮出局的人的下一个人开始从 11 报数,报到 22 就停止且报到 22 的这个人出局。第三轮从上一轮出局的人的下一个人开始从 11 报数,报到 33 就停止且报到 33 的这个人出局。第 n - 1n1 轮从上一轮出局的人的下一个人开始从 11 报数,报到 n - 1n1 就停止且报到 n - 1n1 的这个人出局。最后剩余的人是幸存者,请问这个人的标号是多少?
输入描述
第一行一个整数表示测试组数:T(0 < T\le5000)T(0<T5000) 。每组数据占一行,包含一个整数 nn,表示 nn 个人围成一圈。
输出描述
TT 行。对每组数据,输出幸存者的编号。
输入样例
223
输出样例
22
Hint
对于第一组数据,一开始报到 11 的人即标号为 11 的人退出,幸存者是 22 号。对于第二组数据,一开始报到 11 的人即标号 11 的人退出。接着 22 号报 1133 号报 22,报到 22 的人即 33 号退出。幸存者是 22 号。

之前做过约瑟夫问题,但当时还比较年轻(......),然后也没有想得太清楚。。。

n个人从0编号一直到n-1,围成一个逆时针的圈,每次淘汰数到k的人。倒推过来,每一次从淘汰数到k的那个人,然后,上一次标号为k的人下一轮标号为0,所以可以得到这一次标号为x的,上一次标号为(x+k)%i,i是上一轮的人数。然后最后剩下的那个人标号是0。从两个人开始倒着推,得到结果。

代码:

#pragma warning(disable:4996)#include <iostream>#include <functional>#include <algorithm>#include <cstring>#include <vector>#include <string>#include <cstdio>#include <cmath>#include <queue>#include <stack>#include <deque>#include <set>#include <map>using namespace std;typedef long long ll;#define INF 0x3fffffffconst ll mod = 1e9 + 7;const int maxn = 5005;int res[maxn];void init(){memset(res, 0, sizeof(res));int i, j, k, n, ans;res[1] = 1;for (i = 2; i <= 5000; i++){ans = 0;for (j = 2; j <= i; j++){ans = (ans + i - j + 1) % j;}res[i] = ans + 1;}}void solve(){int k;scanf("%d", &k);printf("%d\n", res[k]);}int main(){#ifndef ONLINE_JUDGE  freopen("i.txt", "r", stdin);freopen("o.txt", "w", stdout);#endifinit();int t;scanf("%d", &t);while (t--){solve();}return 0;}


0 0
原创粉丝点击