博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POJ——3517
阅读量:6951 次
发布时间:2019-06-27

本文共 2941 字,大约阅读时间需要 9 分钟。

  题目链接:

  其实基本就是约瑟夫环问题,最终accepted的answer是看过相关资料才写出来的:

 

  无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂 度高达O(nm),

当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。

为了讨论方便,先把问题稍微改变一下,并不影响原意:

问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。

 

我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始):

k k+1 k+2 ... n-2, n-1, 0, 1, 2, ... k-2 并且从k开始报0。 现在我们把他们的编号做一下转换:

k --> 0

k+1 --> 1

k+2 --> 2

... ...

k-2 --> n-2

k-1 --> n-1

  变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:

例如x是最终的胜利者,那么根 据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!

变回去的公式很简单,相信大家都可以推出来:

x=(x+k)%n

如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。(n-2)个人的解呢?当然是先求(n-3)的 情况 ---- 这显然就是一个倒推问题!

代码:Accepted:

1 #include
2 #define MAX 100 3 4 using namespace std; 5 6 int main(){ 7 int n = 1, k = 1, m = 1, cnt =0; 8 int rel[MAX] = { 0 }; 9 while((n!=0) && (k!=0) && (m!=0))10 {11 cin >> n >> k >> m;12 if((n!=0) && (k!=0) && (m!=0))13 {14 int f=0;15 for(int i=2;i
< cnt;i++)23 {24 cout << rel[i] << endl;25 }26 return 0;27 }

  我用链表写的,总超时,后面我对其进行了很多优化,也通不过,我怀疑只能通过数学解法做,也列出来吧

  链表的约瑟夫问题太有名了,以至于我神马都没想,就直接用链表做了

1 #include 
2 #define MAX 100 3 using namespace std; 4 5 typedef struct node 6 { 7 int num; 8 node* nxt; 9 }node;10 typedef node* Lst;11 12 int Final(int n, int k, int m);13 14 int main()15 {16 int n = 1, k = 1, m = 1, cnt =0;17 int rel[MAX] = { 0 };18 while((n!=0) && (k!=0) && (m!=0))19 {20 cin >> n >> k >> m;21 if((n!=0) && (k!=0) && (m!=0))22 {23 rel[cnt] = Final(n,k,m);24 cnt++;25 }26 27 }28 29 for(int i = 0;i < cnt;i++)30 {31 cout << rel[i] << endl;32 }33 34 /*for(int i = 0; i < 2*n;i++)35 {36 cout << head->num<
nxt;38 }*/39 40 return 0;41 }42 int Final(int n, int k, int m)43 {44 Lst L, head, tmp;45 L = new node;46 L->nxt = L;47 head = L;48 L->num = 1;49 50 for(int i = 1; i < n;i++)51 {52 //Insert(L, i+1)53 tmp = new node;54 tmp->num = i+1;55 head->nxt = tmp;56 tmp->nxt = L;57 head = tmp;58 //cout << head->num << " \t";59 }60 int stonecnt = n;61 head = L;62 for(int i = 0;i < (m-1)%n; i++)63 {64 tmp =head;65 head = head->nxt;66 }67 stonecnt--;68 Lst del = head;69 head = head->nxt;70 tmp->nxt = head;71 delete del;72 while(stonecnt > 1)73 {74 for(int i = 0;i < (k-1)%stonecnt; i++)75 {76 tmp =head;77 head = head->nxt;78 }79 stonecnt--;80 del = head;81 head = head->nxt;82 tmp->nxt = head;83 delete del;84 }85 int rel = head->num;86 delete head;87 return rel;88 }

转载于:https://www.cnblogs.com/moondark/archive/2012/07/11/2587169.html

你可能感兴趣的文章
对大学努力的理解
查看>>
name_save matlab
查看>>
Nginx服务器中的Socket切分,需要的朋友可以参考下
查看>>
leetcode 46. 全排列
查看>>
美团点评智能支付核心交易系统的可用性实践
查看>>
关于asp.net中链接数据库的问题
查看>>
kubernetes 1.14安装部署metrics-server插件
查看>>
IEEE754标准浮点格式
查看>>
嵌入式系统内存泄漏检测
查看>>
flAbsPath on /var/lib/dpkg/status failed 解决 Cydia 红字
查看>>
在本地测试一次成功的AJAX请求
查看>>
淘淘商城第二天
查看>>
配置和修改参数
查看>>
DS06--图
查看>>
C#通过XElement写入XML文件
查看>>
1 0 .2 用于监视的工具和技术
查看>>
洛谷2142高精度减法(模板)
查看>>
First Missing Positive && missing number
查看>>
SharePoint服务器端对象模型 之 使用CAML进行数据查询(Part 4)
查看>>
10条设计师应该知道的字体设置技巧
查看>>