递归算法——约瑟夫问题

经典的约瑟夫问题:

问题描述:n个人围成一圈,每隔k个杀死一个,问最后的幸存者的编号

假设标号是0~n-1,幸存者是f[n]

1、特殊情况:f[1]=0

2、一般情况:f[i] = (f[i-1]+k)%i

第i个被杀的与第i-1个被杀的人之间的关系可以看下面的推导过程

游戏开始时排序:

0、1、2、3、4、5、6、7、8……n-1

第一次被杀死的人的标号是k-1,还剩下n-1个人,此时的排序是:

k、k+1、k+2、k+3……n-1、0、1、2……k-3、k-2  ==> (*)

对这n-1个数重新排序:

0、1、2、3……n-5、n-4、n-3、n-2  ==> (**)

从上面这两个式子中可以发现:( (**) + k ) % n = (*)

//写法1:比较费时,对初学者来说有助于理解 
#include <bits/stdc++.h>
using namespace std;
int fun(int m,int k,int i)
{
    if(i==1)
        return (m+k-1)%m;
    else
        return (fun(m-1,k,i-1)+k)%m;
}
int main()
{
	int n, k;
	while(~scanf("%d%d", &n, &k))
	{
		for(int i=1;i<=n;i++)
        	printf("第%2d个被杀的人:%2d\n",i,fun(n,k,i)+1);
	}
    return 0;
}
//写法二:比较节省时间的 
#include <bits/stdc++.h>
using namespace std;
int main()
{
	int n, k;
	while(~scanf("%d%d", &n, &k))
	{
		int ans=0;
		for(int i=2; i<=n; i++)
		{
			ans = (ans+k)%i;
		}
		printf("幸存者的编号是%2d\n", ans+1);
	}
	return 0;
} 

题目链接:【HDU 2211】杀人游戏


题目链接:【HDU 2925】 Musical Chairs


题目链接:【HDU 5643】 King’s Game (约瑟夫问题的变形)

n个士兵围成一圈,从第一个开始报数,第i次报数时,报到i的士兵出局,问最后一个幸存的士兵的编号是多少

递推过程跟经典的约瑟夫问题一样,我们可以得到式子f[i] = (f[i-1]+k-1)%num[i]

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
int n, ans;
int fun(int k, int num)
{
	if(k==n) 
	{
		ans=0;
		return (ans+k-1)%num;
	}
	else 
	{
		ans=(fun(k+1, num-1)+k-1)%num;
		return ans;
	}
}
int main()
{
	int t;
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d", &n);
		printf("%d\n", fun(1,n+1)+1);
	}
	return 0;
}

    原文作者:递归算法
    原文地址: https://blog.csdn.net/YHYYXT/article/details/50868070
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞