递推法求解约瑟夫问题
来源:互联网 发布:淘宝详情页模板怎么做 编辑:程序博客网 时间:2024/06/07 21:11
递推法求解约瑟夫问题
假设有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
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=464&page=show_problem&problem=4140
/**========================================== * 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
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=465&page=show_problem&problem=4198
/**========================================== * 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;}
0 0
- 递推法求解约瑟夫问题
- 求解约瑟夫环问题
- 约瑟夫问题求解(C++)
- 约瑟夫问题的求解
- 约瑟夫问题求解
- 约瑟夫问题求解
- 约瑟夫问题求解
- 约瑟夫问题求解
- 约瑟夫问题java求解
- 约瑟夫问题C++求解
- 约瑟夫问题求解
- 约瑟夫问题求解
- 约瑟夫问题简单求解
- 约瑟夫环问题求解
- 约瑟夫问题求解
- 约瑟夫问题求解
- 约瑟夫问题递归求解
- 约瑟夫问题的求解
- 分分钟让移动端崩溃重启的代码
- javascript的String对象截取字符串的方法
- Qt下定时器的使用
- 利用pageControl 来做自动轮播
- Spring MVC学习详解
- 递推法求解约瑟夫问题
- zabbix 监控 nginx
- K-means聚类算法
- jquery刷新iframe页面的方法
- Verilog中$fopen $fdisplay $fclose的用法
- FragmentActivity和Activity的区别
- Java笔记17:导出可执行jar包
- Cocos物理引擎刚体的3种掩码
- Android系统信息和安全机制(学习笔记)