约瑟夫环问题——(Hdu-5643,King's Game)

约瑟夫环问题解释:

当剩下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 Game

Time 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(1n5000)  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  n1  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<T5000) , 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
      
      
2 2 3
 

Sample Output
      
      
2 2


解题思路:稍加变化的约瑟夫环问题,每次变换了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;
}


















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值