经典的约瑟夫问题:
问题描述: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;
}