【迭代加深】UVA - 12558 Egyptian Fractions

题目

题目描述

Given a fraction a/b, write it as a sum of different Egyptian fraction. For example, 2/3 = 1/2 + 1/6.There is one restriction though: there are k restricted integers that should not be used as a denominator.
For example, if we can’t use 2..6, the best solution is:
2/3 = 1/7 + 1/9 + 1/10 + 1/12 + 1/14 + 1/15 + 1/18 + 1/28
The number of terms should be minimized, and then the large denominator should be minimized.If there are several solutions, the second largest denominator should be minimized etc.

输入

The first line contains the number of test cases T (T ≤ 100). Each test case begins with three integers a, b, k (2 ≤ a < b ≤ 876, 0 ≤ k ≤ 5, gcd(a, b) = 1). The next line contains k different positive integers not greater than 1000.

输出

For each test case, print the optimal solution, formatted as below. Extremely Important Notes It’s not difficult to see some inputs are harder than others. For example, these inputs are very hard input for every program I have:
596/829=1/2+1/5+1/54+1/4145+1/7461+1/22383
265/743=1/3+1/44+1/2972+1/4458+1/24519
181/797=1/7+1/12+1/2391+1/3188+1/5579
616/863=1/2+1/5+1/80+1/863+1/13808+1/17260
22/811=1/60+1/100+1/2433+1/20275
732/733=1/2+1/3+1/7+1/45+1/7330+1/20524+1/26388
However, I don’t want to give up this problem due to those hard inputs, so I’d like to restrict the input to “easier” inputs only. I know that it’s not a perfect problem, but it’s true that you can still have fun and learn something, isn’t it?
Some tips:

  • Watch out for floating-point errors if you use double to store intermediate result. We didn’t use
    double.
  • Watch out for arithmetic overflows if you use integers to store intermediate result. We carefully
    checked our programs for that.

样例输入

5
2 3 0
19 45 0
2 3 1 2
5 121 0
5 121 1 33

样例输出

Case 1: 2/3=1/2+1/6
Case 2: 19/45=1/5+1/6+1/18
Case 3: 2/3=1/3+1/4+1/12
Case 4: 5/121=1/33+1/121+1/363
Case 5: 5/121=1/45+1/55+1/1089

题目大意

将一个分数分解成几个单位分数的和,有k个数不能用(见后两个样例)。例如:
23=12+16 2 3 = 1 2 + 1 6

1945=15+16+118 19 45 = 1 5 + 1 6 + 1 18
单位分数分母不能一样。

当然,有无数组解,分母递增输出分数最少的解。满足这个条件的情况下,最后一个分母尽量小,然后倒数第2个分母尽量小,以此类推。

分析

迭代加深?

这种搜索题和一般的题有一个显著的区别:不知道终止条件,或者说终止条件不好判断。这个时候我们人为制定一个 MaxD M a x D ,即最大搜索深度,一旦超过这个深度就返回,然后判断能否找到解,找到解就可以输出了。

这样将最大搜索深度不断加大的方法就是迭代加深了。

枚举加数?

定义 dfs(i,A,B) d f s ( i , A , B ) ,表示现在是第i层,还需要凑 AB A B
显然,最小到大枚举分母,我们需要先处理当前分母的范围。

乐观估计

这是一个很重要的方法,用于剪枝。

  • 设当前能使用的最大分母(使得分数值最小)为 t t ,乐观地认为现在每个分母可以相同,则:
    1t×(MaxDi+1)=AB
    t=(MaxDi+1)BA t = ( M a x D − i + 1 ) ∗ B A

  • 若分母为 k k 满足条件,则:
    1kAB
    kBA k ≥ B A

  • 当然,当前分母一定要比上一个分母大。

综上:将现在已经枚举到的分母存在Tmp数组中,当前枚举的分母为 k k ,则:

max(BA,Tmp[i1]+1)k(MaxDi+1)BA

递归

下一层为 dfs(i+1,AB1k) d f s ( i + 1 , A B − 1 k ) ,即 dfs(i+1,AkBBk) d f s ( i + 1 , A k − B B k )

代码

#include<set>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

#define MAXN 1000
#define LL long long
int MaxD,Get;//Get为1表示找到了
LL Ans[MAXN+5],Tmp[MAXN+5];
set<LL> No;//保存不能用的分母

LL gcd(LL a,LL b){//用于约分
    return !b?a:gcd(b,a%b);
}

void dfs(int i,LL A,LL B){
    LL d=gcd(A,B);
    A/=d,B/=d;//先约个分
    if(A==1&&B>Tmp[i-1]&&!No.count(B)){
        Tmp[i]=B;
        int j=i;
        while(Tmp[j]==Ans[j]&&j>=1)
            j--;
        //要保证Tmp为当前最优解
        if(Tmp[j]<Ans[j])
            memcpy(Ans,Tmp,sizeof Tmp);
        Get=1;
        return;
    }
    if(i>MaxD) return;
    LL Max=(MaxD-i+1)*B/A;
    for(LL k=max(B/A,Tmp[i-1]+1);k<=Max;k++){
        if(A*k-B<0||No.count(k)) continue;//不符合条件
        if(Get) Max=min(Max,Ans[MaxD]-1);//找到了,更新最大值
        Tmp[i]=k;
        dfs(i+1,A*k-B,B*k);
    }
}

int main(){
    int T=read(),cas=0;
    while(T--){
        MaxD=Get=0;
        No.clear();
        memset(Tmp,0,sizeof Tmp);
        memset(Ans,0x7f,sizeof Ans);//Ans一定要初始化极大值
        LL A=read(),B=read(),K=read();
        while(K--)
            No.insert(read());
        while(!Get){
            MaxD++;
            dfs(1,A,B);
        }
        printf("Case %d: %lld/%lld=1/%lld",++cas,A,B,Ans[1]);
        for(int i=2;i<=MaxD;i++)
            printf("+1/%lld",Ans[i]);
        puts("");
    }
}
Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
在描绘希腊名字时,埃及人还有其他的方式,而不仅仅是拼写出来。在古埃及时期,虽然埃及和希腊有一定的文化交流,但由于语言和文化的差异,埃及人可能会使用其他手段来描绘希腊名字。以下是几种可能的方法: 1. 使用象形文字:埃及象形文字是一种图画式的文字,可以用于表达不同的语言和文化。如果一个埃及人想要描绘一个希腊名字,他们可以尝试使用一些象形文字符号来表示这个名字的含义或特征。 2. 使用彩绘或浮雕:在古埃及的墓葬、神庙和石碑上,经常可以见到彩绘和浮雕的形象。埃及人可以通过在这些艺术品中描绘希腊名字的人物形象或特征,来表达这个名字。 3. 使用符号或代表性图案:埃及人也可以使用一些特定的符号或代表性图案来表达希腊名字。例如,他们可以用一只鹰来代表希腊主神宙斯(Zeus),或者用戴有橄榄树枝的头冠来代表希腊女神雅典娜(Athena)。 4. 结合埃及和希腊元素:埃及人还可以尝试将埃及和希腊元素结合在一起,以表达一个希腊名字。例如,他们可以将有埃及特色的头部形象与希腊特色的服饰结合起来,来代表一个希腊神或英雄的名字。 总之,埃及人在描绘希腊名字时,并不仅限于简单地拼写出来。他们可以运用象形文字、彩绘、浮雕、符号、代表性图案等多种方式,通过视觉表达来呈现希腊名字的含义与特征。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值