递推法求解约瑟夫问题
假设有n个人围成一圈,编号为0,1,2,3,...,n-1,现在从编号为0的人开始 1到k 报数,报k的人退出圈子,下一个人继续从1到k报数。直到所有人退出圆圈。
问:最后一个退出圆圈的人编号是多少?
求解:
利用递推法:
1.起点(边界): 考虑人数为1的情况
因为只有编号为0的人,所以最后出去的一定是0
dp[1]=0;
2.假设已经求出人数为x-1的情况 (即最后出去人的编号),现在我要考虑求解人数为x的情况。
我们先分析一下,从x个人中退出x个人的过程:
1.先退出1个人
首先编号为0到k-1的人报数,k-1退出
2.再退出x-1个人
之后再退出剩下的x-1个人
这个时候就可以写出状态专移方程了!!
dp[x]=(d[x-1]+k)%x;
为什么这样的?因为剔除了1个人(就是k-1)之后,剩下x-1个人,将k作为编号0,那么dp[x-1]就是x-1情形时的最后一人,也就是所求(也就是x情形时的最后一人)
那么我们只需将dp[x-1]在x-1情形下的编号转化为x情形下的编号即可,即+k。
别忘了取模!
1.uva 1394 - And Then There Was One
/**==========================================
* This is a solution for ACM/ICPC problem
*
* @source£ºuva 1394 - And Then There Was One
* @type: dp
* @author: wust_ysk
* @blog: http://blog.csdn.net/yskyskyer123
* @email: 2530094312@qq.com
*===========================================*/
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF =0x3f3f3f3f;
const int maxn = 10000;
int n,k,m;
int dp[maxn+5];
int main()
{
while(~scanf("%d%d%d",&n,&k,&m)&&(n||k||m) )
{
dp[1]=0;
for(int i=2;i<n;i++)
{
dp[i]=(dp[i-1]+k)%i;
}
dp[n]= (dp[n-1]+m )%n;
printf("%d\n",dp[n]+1);
}
return 0;
}
2.uva 1452 - Jump
/**==========================================
* This is a solution for ACM/ICPC problem
*
* @source£ºuva 1452- Jump
* @type: dp
* @author: wust_ysk
* @blog: http://blog.csdn.net/yskyskyer123
* @email: 2530094312@qq.com
*===========================================*/
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF =0x3f3f3f3f;
int ans[4];
bool vis[3];
int n,k;
int main()
{
int T;scanf("%d",&T);
while(T--)//ans[k]表示倒数第k个
{
scanf("%d%d",&n,&k);
ans[1]=0;
memset(vis,0,sizeof vis);
ans[1]= (ans[1]+k)%2;
vis[ ans[1] ]=1;
ans[2]=vis[0]?1:0;
memset(vis,0,sizeof vis);
ans[1]=(ans[1]+k)%3;
ans[2]=(ans[2]+k)%3;
vis[ ans[1] ]=1;
vis[ ans[2] ]=1;
for(int i=0;i<3;i++) if(!vis[i])
{
ans[3]=i;
break;
}
for(int i=4;i<=n;i++)
{
ans[1]=( ans[1]+k)%i;
ans[2]=( ans[2]+k)%i;
ans[3]=( ans[3]+k)%i;
}
ans[1]++,ans[2]++,ans[3]++;
printf("%d %d %d\n",ans[3],ans[2],ans[1]);
}
return 0;
}