约瑟夫环问题解释:
当剩下n个人的时候,他们的编号设为为0、1、2、3、4.....n-1。假定最后编号为dp[n]的人会留下来
因为数到m的人会出列,那么在当前回合编号为 (m-1)%n 的人会出列,再将当前回合编号中为 m%n 的人当做下一轮编号为0的人,以此类推,当前回合编号为 (m+i)%n 的人将成为下一回合编号为i的人
当前回合(m+i)%n ——> i 下一回合
下一回合 i ——> (i+m)%n 上一回合
得到递推式:dp(n) = ( m+dp(n-1) )%n (m 为当前回合数到第几个人出列 dp(n)为最后留下来的人在 n个人回合时的编号,dp(n-1)为最后留下来的人在n-1个人回合时的编号。
由于dp(1) = 0(最后留下来的人在一个人的回合时编号为0),所以可以反向递推回去最后留下来的人在n 个人回合时的编号。
例题HDU-5643
题目描述:
King's GameTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 562 Accepted Submission(s): 311
Problem Description
In order to remember history, King plans to play losephus problem in the parade gap.He calls
n(1≤n≤5000)
soldiers, counterclockwise in a circle, in label
1,2,3...n
.
The first round, the first person with label 1 counts off, and the man who report number 1 is out. The second round, the next person of the person who is out in the last round counts off, and the man who report number 2 is out. The third round, the next person of the person who is out in the last round counts off, and the person who report number 3 is out. The N - 1 round, the next person of the person who is out in the last round counts off, and the person who report number n−1 is out. And the last man is survivor. Do you know the label of the survivor?
Input
The first line contains a number
T(0<T≤5000)
, the number of the testcases.
For each test case, there are only one line, containing one integer n , representing the number of players.
Output
Output exactly
T
lines. For each test case, print the label of the survivor.
Sample Input
Sample Output
|
解题思路:稍加变化的约瑟夫环问题,每次变换了m的值,因为是从1开始编号,所以最后留下来的人的序号为dp[n]+1。
AC代码:
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
int dp[6666];
int main()
{
int T;
cin >> T;
while(T--)
{
memset(dp, 0, sizeof(dp));
int n;
cin >> n;
for(int i = 2; i <= n; i++)
{
dp[i] = ( (n-i+1) + dp[i-1])%i;
}
dp[n] += 1;
cout << dp[n] << endl;
}
return 0;
}