【Codevs1288】埃及分数

Position:


Description

  在古埃及,人们使用单位分数的和(形如1/a的, a是自然数)表示一切有理数。 如:2/3=1/2+1/6,但不允许2/3=1/3+1/3,因为加数中有相同的。 对于一个分数a/b,表示方法有很多种,但是哪种最好呢? 首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越 好。 如: 19/45=1/3 + 1/12 + 1/180 19/45=1/3 + 1/15 + 1/45 19/45=1/3 + 1/18 + 1/30, 19/45=1/4 + 1/6 + 1/180 19/45=1/5 + 1/6 + 1/18. 最好的是最后一种,因为1/18比1/180,1/45,1/30,1/180都大。 给出a,b(0 < a < b < 1000),编程计算最好的表达方式。

Input

a b

Output

若干个数,自小到大排列,依次是单位分数的分母。

Sample Input

19 45

Sample Output

5 6 18

Solution

精简版本

给定一个分数 A/B,要将其转换为单位分数之和。要求单位分数数量最少,且每个分数都不同。

Source

普通搜索枚举哪个数可以填显然会TLE,它会不断搜下去,爆LL,爆栈。
那么怎么解决呢?采用迭代加深算法,限定分成的数目,如果当前可以,即为最小输出方案即可。
剪枝(见check函数):当前可以搜的最大分数(由分数从大到小搜索)×剩余块数 < 还要搞的分数,就可以return了,因为之后不可能有解。

Code

// <math.cpp> - Wed Sep 28 08:14:53 2016
// This file is made by YJinpeng,created by XuYike's black technology automatically.
// Copyright (C) 2016 ChangJun High School, Inc.
// I don't know what this program is.

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#define IN inline
#define RG register
using namespace std;
typedef long long LL;
const int MAXN=100010;
const int MAXM=100010;
inline LL gi() {
	register LL w=0,q=0;register char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')q=1,ch=getchar();
	while(ch>='0'&&ch<='9')w=w*10+ch-'0',ch=getchar();
	return q?-w:w;
}
int n;LL as[MAXN];
IN bool check(LL a,LL b,LL c,LL d){
    if(a*d>b*c)return 0;
    else return true;
}
IN void dfs(LL x,LL y,LL f,int d){
    if(x<0)return;
    if(d==1){
        if(x==1&&y>=f){
            printf("%d\n",n);
            for(int i=n;i>=2;i--)
                printf("%lld ",as[i]);
            printf("%lld",y);exit(0);
        }
        return;
    }
    for(RG LL i=f,g;check(x,y,d,i);i++){
        as[d]=i;g=__gcd(x*i-y,y*i);
        dfs((x*i-y)/g,y*i/g,i+1,d-1);
    }
}
int main()
{
	freopen("math.in","r",stdin);
	freopen("math.out","w",stdout);
	int x=gi(),y=gi();
    for(int i=1;;i++)n=i,dfs(x,y,1,i);
	return 0;
}

Codevs这个

注意这题和上面那道普通题不同:加数个数相同的,最小的分数越大越好。

Source

最后统计答案时,不直接exit(0);让它将这一层(迭代的深度)全搜完,统计最优答案。

Code

// <math.cpp> - Wed Sep 28 08:14:53 2016
// This file is made by YJinpeng,created by XuYike's black technology automatically.
// Copyright (C) 2016 ChangJun High School, Inc.
// I don't know what this program is.

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#define IN inline
#define RG register
using namespace std;
typedef long long LL;
const int MAXN=100010;
const int MAXM=100010;
inline LL gi() {
	register LL w=0,q=0;register char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')q=1,ch=getchar();
	while(ch>='0'&&ch<='9')w=w*10+ch-'0',ch=getchar();
	return q?-w:w;
}
int n;LL as[MAXN],sa[MAXN];bool flag;
IN bool check(LL a,LL b,LL c,LL d){
    if(a*d>b*c)return 0;
    else return true;
}
IN void dfs(LL x,LL y,LL f,int d){
    if(x<0)return;
    if(d==1){
        if(x==1&&y>=f){
            if(y<sa[1]){
                flag=true;sa[1]=y;
                for(int i=n;i>=2;i--)sa[i]=as[i];
            }
        }
        return;
    }
    for(RG LL i=f,g;check(x,y,d,i);i++){
        as[d]=i;g=__gcd(x*i-y,y*i);
        dfs((x*i-y)/g,y*i/g,i+1,d-1);
    }
}
int main()
{
	freopen("math.in","r",stdin);
	freopen("math.out","w",stdout);
	int x=gi(),y=gi();flag=false;sa[1]=1e17;
    for(int i=1;;i++){
        n=i,dfs(x,y,1,i);
        if(flag){
            for(int i=n;i;i--)printf("%lld ",sa[i]);return 0;
        }
    }
	return 0;
}

原型

参考我的博客:SWUST626 分数分解

posted @ 2016-09-28 15:23  _Mashiro  阅读(255)  评论(0编辑  收藏  举报