您的位置:首页 > 移动开发

追赶法-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就对了。

完。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: