追赶法-ZOJ-1601-Integer Approximation
2012-04-17 11:58
218 查看
#include<iostream>
#include<cstdlib> #include<vector> #include<map> #include<cstring> #include<string> #include<algorithm> #include<ctype.h> #include<fstream> #include<string.h> #include<stdio.h> #include<math.h> #include<stack> #include<queue> #include<ctime> //#include<conio.h> using namespace std; const int INF_MAX=0x7FFFFFFF; const int INF_MIN=-(1<<31); const double eps=1e-10; const double pi=acos(-1.0); #define S(a) scanf("%d",&a) #define SS(a,b) scanf("%d%d",&a,&b) #define SSS(a,b,c) scanf("%d%d%d",&a,&b,&c) #define P(a) printf("%d\n", a) #define PP(a,b) printf("%d %d\n",a,b) #define PPP(a,b,c) printf("%d %d %d\n",a,b,c) #define chmin(a,b) ((a)<(b)?(a):(b)) #define chmax(a,b) ((a)>(b)?(a):(b)) template<class T> inline T gcd(T a,T b)//NOTES:gcd( {if(a<0)return gcd(-a,b);if(b<0)return gcd(a,-b);return (b==0)?a:gcd(b,a%b);} template<class T> inline T lcm(T a,T b)//NOTES:lcm( {if(a<0)return lcm(-a,b);if(b<0)return lcm(a,-b);return a*(b/gcd(a,b));} typedef pair<int, int> PII; typedef vector<PII> VPII; typedef vector<int> VI; typedef vector<VI> VVI; typedef long long LL; int dir_4[4][2]={{0,1},{-1,0},{0,-1},{1,0}}; int dir_8[8][2]={{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1}}; //下,左下,左,左上,上,右上,右,右下。 //******* WATER **************************************************************** double A; long long L; double dis_new; double dis_best;//会不会有两个相等的情况? long long N; long long D; long long best_N; long long best_D; double dis(double a, double b) { return fabs( A - (a/b) ); } void initial() { N = 1; D = 1; dis_best = dis(N,D); best_N = N; best_D = D; return ; } /* void run()//会不会相等,会不会有多组? { dis_new = dis(N,D); while( dis_new < dis_old ) { dis_old = dis_new; N = temp_N; D = temp_D; if( (double)N/D < A ) { temp_N++; } else if( (double)N/D > A ) { temp_D++; } else return; dis_new = dis(temp_N, temp_D); //cout<<"N="<<N<<" D="<<D<<endl; //cout<<"dis_new="<<dis_new<<" dis_old="<<dis_old<<endl; } return ; } */ void run() { while( N < L && D < L ) { if( (double)N/D < A ) { N++; } else { D++; } dis_new = dis(N,D); if( dis_new < dis_best ) { best_N = N; best_D = D; dis_best = dis_new; } } return ; } void output() { cout<<best_N<<" "<<best_D<<endl; return ; } int main() { //freopen("input.txt","r",stdin); //freopen("output.txt","w",stdout); while( scanf("%lf%I64d",&A, &L) != EOF ) { initial(); run(); output(); } return 0; //printf("%.6f\n",(double)clock()/CLOCKS_PER_SEC); }
点击打开链接
我先把代码附在上面,题目就是上面的链接。
题目要求:给定一个小数A,用分数N/D来近似表示A,同时要求N和D小于等于L。
思维路线:bingshen在他的博客中写到了他最开始的做法:首先枚举N或者D,然后用二分查找的方法来求得在已知N(或D)的情况下最逼近A值的D(或者N)枚举复杂度O (n),二分复杂度log(n),所以此方法的复杂度是O(n*log(n));但是结果bingshen说事TLE。悲剧的bingshen啊!
追赶法路线:首先假设存在一个N_best和D_best,能够让 fabs(A-(N/D)) 最小(以下简称fabs),那么首先设置N = 1,D = 1,然后如果 A - (N/D) < 0 那么就N++,如果 A -(N/D) > 0,那么就D++,如果 A - (N/D) == 0,那么N++,或者D++,每次保存目前最佳的N_best和D_best.如此一直进行到N>L或者D>L为止。时间复杂度O(n).
问题和解答:1.为什么”如果 A - (N/D) == 0,那么N++,或者D++。”都可以?
这个是因为我们在这个过程中已经找到了fabs==0的值了,所以说N_best和D_best已经确定了,这时候也可以让程序停止,算是一种优化吧!
2.为什么这个算法可行?
这个问题可以转化为" 为什么这个算法一定能找到N_best和D_best"。假设N_best和D_best都大于1,在N和D逐渐更新的过程中,假如说N更新到了N_best(或者D更新到了D_best),这个时候如果更新N(或者更新D)就是错的,这个算法必须保证更新的是D_best(或者更新N)。
(1 )假如N_best/D_best > A ,这时候 N / D_best 一定是 < A 的,因为 N<N_best ,同时 N/D_best > A ,那么这时候N是比N_best更加合适作为best。这时候因为小于A,所以说一定是D++;
(2 )假如N_best/D_best < A, 这时候 N/D_best 一定是 < A 的,所以理所应当应该D++;
括号里的,如果是D首先更新到D_best呢?
(1 ) 假如N_best/D_best > A, 这时候N/D_best 一定 < A 的,N++;(分析同上)
(2)假如N_best/D_best < A,这时候N/D_best一定是<A的,N++;
综上,最佳值一定是算法所能找到的。
BUG反思:过程中考虑会不会有多组满足的值,比如说3 100 这个数据,最小的是3 1,最大的是99 33,这是OJ的一个BUG吧!
自己写代码有一个错误,就是没有考虑到N和D的值超过L,因为自己是在满足N<=L&&D<=L的情况下还有可能N++和D++,所以可能超过,循环条件改为N<L&&D<L就对了。
完。
相关文章推荐
- ZOJ1601:Integer Approximation
- ZOJ 1601. Integer Approximation
- zoj 1601
- Poj 1650 & Zoj 1601 Integer Approximation (追赶法,分数逼近实数)
- ZOJ-1601
- zoj 1601 Count the Colorst(线段树)
- POJ 1650,ZOJ 1601追赶法
- zoj 1382 A Simple Task
- ZOJ-3410-Layton's Escape_贪心
- ACM zoj 1789(并查集实现)
- zoj 2532 Internship【最小割】
- zoj 1715 When Can We Meet?
- Poj 1967 &&Zoj 2183 Alibaba
- ZOJ - 3229 Shoot the Bullet(有源有汇上下界最大流)
- wzoj install
- zoj 2345 Gold Coins
- ZOJ 2100 Seeding
- ACM学习历程—ZOJ 3777 Problem Arrangement(递推 && 状压)
- ZOJ——1197 Sorting Slides
- ZOJ 3681 E - Cup 2