POJ 1012 Timing Limit Exceed问题
来源:互联网 发布:卖衣服打折怎么计算法 编辑:程序博客网 时间:2024/06/05 15:23
Description
Suppose that there are k good guys and k bad guys. In the circle the first k are good guys and the last k bad guys. You have to determine such minimal m that all the bad guys will be executed before the first good guy.
Input
Output
Sample Input
340
Sample Output
530
在看到POJ 1012这个题之后,首先想到这个问题就是容易,直接用循环查询,就可以啦。于是就写出了下面的程序,谁知道提交竟然会去超时。。。
#include<stdio.h>#include<string.h>#define MAX 28int main(void){ int k,kk,i,m,count=0,countBad=0; int c[MAX]; scanf("%d",&k); while(k){m=k+1;kk=2*k;countBad=0;count=0;memset(c,0,sizeof(c));for(i=1;i<=kk;i=(++i)%(kk+1)==0?1:i){//这里表达式3,有点乱。其实,若是以数组下标0开始对人编号,在对有取模运算的表达式时会很方便 if(countBad==k)break; if(c[i]==1)continue; count++; if(count==m && i<=k){m++;count=0;countBad=0;memset(c,0,sizeof(c));i=0;continue;} else if(count==m){c[i]=1;countBad++;count=0; }}printf("%d\n",m);scanf("%d",&k); } return 0;}
分析上面的算法复杂度:
普通的Joseph环问题,有n个人,开报数m的话,只剩下最后一个人的算法复杂度为:(n-1)*m,这个算法若不是找出最后一个人,若出第k个人的算法复杂度应该是k*m.
所以Joseph在找出第k个人的时候,是和这个环的长度是无关的。
而在上面代码算法中,m是不确定的,我们从m=k+1开始,找出k个人,和算法复杂度为
(k-1)*m+(k-1)*(m+1)+...+(k-1)*(m+i)+...+>= (k-1)*m+(k-1)*(m+1)+...+(k-1)*(m+i)+...+k*(m+w) ,前面用k-1标记,说明我们在后面找不k个bad guys。
>=(k-1)[ m+(m+1)+....+(m+w)]=(k-1)[(w+1)m+w(w+1)/2)]=O(kwm+kw^2/2) , 因为w是不确定的,所以这个算法复杂度是Ω(n)=kw^2. 记号(Ω是>=的意思)
在上面程序运行进,当k=1,..13时,w对应的值为{ 2, 7, 5, 30, 169, 441, 1872, 7632, 1740, 93313, 459901, 1358657, 2504881 }-k;
对于2504881^2这样的时间复杂度,确实是很长很长啦。
所以利用枚举算法来解决该问题显然是不行的。所以我们应该用数学的方法来解决该问题。
其实Joseph Problem是有一个递推公式的:‘
环中有n个人,从0开始编号(0,1, ......,n-1) 依次报数m
第i轮出局的人为f(i)=(f(i-1)+m-1)%(n-i+1),f(0)=0; (参考wikipedia)
注意:第i轮出局的人f(i)返回的不是他在第一轮所在编号,而在第i轮,删除i-1人之后的下标。
如(0,1,2,3,4,5)这6个人报5的话,其下标依次为第一轮: 人 1,2,3,4,5,6
下标编号:(0,1,2,3,4,5)从第0号开始报数,出局的为5,其编号为f(1)=4 。
第二轮 人 : 1,2,3,4,6
下标编号:(0,1,2,3,4)从f(1)=4编号开始报数,从出局的为4,其编号为f(2)=3。
第三轮 人 : 1,2,3,6
下标编号:(0,1,2,3)从f(2)=3编号开始报数,从出局的为6,其编号为f(3)=3。
这样可以看出,利用上公式的话,只要找出的前k轮找出的下标大于k就OK了。
利用数学公式,而不是利用枚举的方法,这时的时间复杂度为:我们不能找出其上限,但是能找出其下线,是Ω(n)=kw^2. 记号(Ω是>=的意思)
代码如下:
#include<stdio.h>int query(int k,int m);int main(void){ int k,m; scanf("%d",&k); while(k){m=k+1;while(1){ if(query(k,m))break; if(query(k,m+1)){m++;break; } m+=(k+1);}printf("%d\n",m);scanf("%d",&k); } return 0;}int query(int k,int m){ int i,f=0,n=k<<1; for(i=0;i<k;i++){f=(m+f-1)%(n-i);if(f<k) return 0; } return 1;}
提交后,还会超时。
可能是因为第次输入k时,都会重新计算。所以解决方法,将1--13的先计算好,结果保存在数组中。然后有重复的k的时候,直接查找数组就可以了,而不需要重新计算了。
这下就会超时了,代码如下:
#include<stdio.h>//这样都会超时,难道要一次运行完成,把全部运算出来,存在数组中。这样//要是者不行的话,那只能用直接打表的方法了。`int query(int k,int m);int main(void){ int i,k,m; int a[13]; for(k=1;k<=13;k++){m=k+1;while(1){ if(query(k,m)){a[k-1]=m;break; } if(query(k,m+1)){a[k-1]=m+1;break; } m+=(k+1);} } while(scanf("%d",&k),k){ printf("%d\n",a[k-1]); } return 0;}int query(int k,int m){ int i,f=0,n=k<<1; for(i=0;i<k;i++){f=(m+f-1)%(n-i);if(f<k) return 0; } return 1;}
- POJ 1012 Timing Limit Exceed问题
- ceel num Exceed Limit
- Memory Limit Exceed C
- Memory Limit Exceed B
- the directory item limit is exceed: limit=1048576问题的解决
- output limit exceed 常见错误
- scanf不判断是否读到EOF导致 output limit exceed
- nginx: [warn] 4000 worker_connections exceed open file resource limit: 1024
- nginx: [warn] 1024 worker_connections exceed open file resource limit: 256
- timing
- POJ 2017 Speed Limit
- POJ 2017 Speed Limit
- poj 2017 Speed Limit
- POJ 2017 Speed Limit
- poj 2017 Speed Limit
- POJ - Speed Limit
- POJ 2017 - Speed Limit
- POJ 2017 Speed Limit
- 如何解决IE浏览器主页被改为2345.com
- java 字节流与字符流的区别
- Android ActivityGroup TabActivity Back键的处理
- 在cocos2d里添加UITextField
- addActionListener
- POJ 1012 Timing Limit Exceed问题
- 收到了TexturePack的使用许可
- Sqlyog字段的各属性的意思
- Session &Cookie
- 品味细节之java方法重载调用细节
- 递归案例
- C++11智能指针
- C# WPF 项目中无法使用Console输出时出现句柄无效的IO异常解决方法
- NYOJ a problem is easy