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

本文解析了约瑟夫环问题及其递推式,并通过一个具体例子(HDU-5643 King's Game)展示了如何求解。该问题涉及递归算法与数学推导,适合初学者学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

约瑟夫环问题解释:

当剩下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;
}


















### HDU 1443 约瑟夫问题解析 #### 题目描述 题目涉及的是经典的约瑟夫环问题的一个变种。给定一个整数 \( k \),表示有 \( k \) 个好人和 \( k \) 个坏人,总共 \( 2k \) 个人围成一圈。编号从 1 到 \( 2k \),其中前 \( k \) 个为好人,后 \( k \) 个为坏人。目标是在不杀死任何好人的前提下,找到可以先消灭所有坏人的最小步数 \( n \)[^5]。 #### 解题思路 为了确保在杀掉第一个好人之前能将所有的坏人都清除,可以通过模拟约瑟夫环的过程来寻找符合条件的最小步数 \( n \)。一种有效的方法是利用动态规划的思想逐步缩小范围直到找到最优解。对于较大的 \( k \),由于数值较大可能导致计算复杂度增加,因此需要考虑算法效率并进行适当优化[^1]。 #### Python 实现代码 下面提供了一个基于Python编写的解决方案: ```python def josephus(k): m = 2 * k def find_min_n(m, start=1): for n in range(1, m + 1): pos = (start + n - 2) % m + 1 if all((pos - i) % m > k or (pos - i) % m == 0 for i in range(n)): return n raise ValueError("No solution found") min_n = None for good_start in range(1, k + 1): try: current_min = find_min_n(m=m, start=good_start) if not min_n or current_min < min_n: min_n = current_min except ValueError as e: continue return min_n if __name__ == "__main__": test_cases = [int(input()) for _ in range(int(input()))] results = [] for case in test_cases: result = josephus(case) print(result) ``` 此段代码实现了上述提到的逻辑,并且能够处理多个测试案例。需要注意的是,在实际应用中可能还需要进一步调整参数以及边界条件以适应不同情况下的需求[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值