题意描述

题目描述的翻译挺清楚的了。

和原题的区别是多了禁用的分母。(还有毒瘤输入输出)

算法分析

显然这道题没有什么很好的数学方法来解决,所以可以使用搜索。

由于不确定深度,深搜显然无穷无尽。

所以一开始考虑使用广搜,如果不加改变空间复杂度显然呈指数级增长。

  1. 使用启发式搜索来实现,但是此题显然没有必要。(有兴趣的可以自行尝试实验)
  2. 使用迭代加深(ID)实现,代码较上一方法更容易实现。

不熟悉 ID 的同学可以先找别的题目了解一下。

假设当前已经到了 \(dep\) 个数,上一次使用的分母是 \(last\),目前迭代的最深次数是 \(d\)。

目前得到的分数和的为 \(\frac{a}{b}\),题目要求的总和是 \(\frac{x}{y}\),当前选的分母是 \(num\)。

那么我们可以确定当前分母的上下界:

  1. \(num\) 的最小值:\(\max\{last+1,\frac{1}{\frac{x}{y}+\frac{a}{b}}\}=\max\{last+1,\frac{b\times y}{b\times x-a\times y}\}\)。
  2. \(num\) 的最大值:\(\frac{\frac{x}{y}-\frac{a}{b}}{d-dep}\)。

解释一下:

对于分母的最小值,由于分母单调递增,所以至少是上一个分母 \(+1\)。

但是由于显然 \(\frac{a}{b}+\frac{1}{num}\leq \frac{x}{y}\),所以还要取 \(\min\)。

对于最大值,显然至少 \((d-dep)\times \frac{1}{num}+\frac{a}{b}\geq \frac{x}{y}\)。

因为分母单调递增,如果即使全部使用当前分母还是不能达到 \(\frac{x}{y}\) 就剪枝。

当然为了精度问题,我们可以将其转化为:

\[b\times y\times (d-dep)+a\times num\times y>=x\times b\times num
\]

注意一下这里 \(dep\) 指的是已经进行的个数(当前的未统计,也就是从 \(0\) 开始)。

到这里读者就可以开始尝试代码实现了,但是还要注意两点:

  1. 分数要约分。
  2. 十年 OI 一场空。

代码实现

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#define int long long
using namespace std; int x,y,q,T,dep,tot=0;
bool vis[1010];
vector<int>now,ans;
set<int>s; int read(){
int x=0,f=1;char c=getchar();
while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0' && c<='9') x=x*10+c-48,c=getchar();
return x*f;
} int gcd(int x,int y){//最大公约数用来约分。
while(y^=x^=y^=x%=y);
return x;
} void chck(){//更新答案。
if(ans.empty() || ans.size()>now.size()){ans=now;return;}
if(now.size()>ans.size()) return;
for(int i=(int)now.size()-1;i>=0;i--){
if(now[i]<ans[i]){
ans=now;return;
} else if(now[i]>ans[i])
return;
}
return;
} void dfs(int d,int last,int a,int b){
//printf("%d %d %d %d\n",d,last,a,b);
if(a*y>b*x) return;//貌似没什么用的小剪枝,避免出现 a/b>x/y 的现象。
if(d>=dep){
if(a*y==b*x) chck();
return;
}
int p=gcd(a,b);//约分。
a/=p,b/=p;
int head=max(last,y*b/(x*b-y*a));//最小值。
for(int i=head;b*y*(dep-d)+a*i*y>=x*b*i;i++){//最大值。
if(s.count(i)) continue;//禁用的不用。
now.push_back(i);
dfs(d+1,i+1,a*i+b,b*i);//加上 1/i 继续 dfs。
now.pop_back();//回溯。
}
return;
} void init(){//多组数据记得清零。
now.clear();ans.clear();
memset(vis,false,sizeof(vis));
s.clear();
return;
} void work(){
init();
x=read(),y=read(),q=read();
int k;
while(q--){k=read();s.insert(k);}//判断是否禁用。
int p=gcd(x,y);x/=p,y/=p;//记得约分。
for(dep=1;ans.empty();dep++)
dfs(0,2,0,1);//注意初值。
printf("Case %d: %d/%d=",++tot,x,y);//毒瘤输出。
printf("1/%d",ans[0]);
for(int i=1;i<(int)ans.size();i++)
printf("+1/%d",ans[i]);
puts("");
return;
} signed main(){
T=read();
while(T--) work();
return 0;
}

完结撒❀。

UVA12558 埃及分数 Egyptian Fractions的更多相关文章

  1. uva12558埃及分数

    1,看这全英文的题目就怪蛋疼的. 2,这输入也是奇奇怪怪的的.3,想要好好做题,理解做题,就得好好看题自己要理解吸收消化.单纯看别人的话,说实话并没有什么用处. 一,看题. 1,首先,枚举的分数肯定不 ...

  2. UVA12558 埃及分数

    #include<iostream> #include<cstdio> #include<set> #include<memory.h> using n ...

  3. UVA12558 Egyptian Fractions (HARD version) (埃及分数,迭代加深搜索)

    UVA12558 Egyptian Fractions (HARD version) 题解 迭代加深搜索,适用于无上界的搜索.每次在一个限定范围中搜索,如果无解再进一步扩大查找范围. 本题中没有分数个 ...

  4. UVA12558 Egyptian Fractions (HARD version)(埃及分数)

    传送门 题目大意 给出一个真分数 a/b,要求出几个互不相同的埃及分数(从大到小),使得它们之和为 a/b (埃及分数意思是分子为1的分数,详见百度百科) 如果有多组解,则分数数量少的优先 如果分数数 ...

  5. UVA-12558 Egyptian Fractions (HARD version) (IDA* 或 迭代加深搜索)

    题目大意:经典的埃及分数问题. 代码如下: # include<iostream> # include<cstdio> # include<cstring> # i ...

  6. uva12558 Egyptian Fractions (HARD version)(迭代深搜)

    Egyptian Fractions (HARD version) 题解:迭代深搜模板题,因为最小个数,以此为乐观估价函数来迭代深搜,就可以了. #include<cstdio> #inc ...

  7. UVa 12558 - Egyptian Fractions (HARD version)

    题目大意: 给出一个真分数,把它分解成最少的埃及分数的和.同时给出了k个数,不能作为分母出现,要求解的最小的分数的分母尽量大. 分析: 迭代加深搜索,求埃及分数的基础上,加上禁用限制就可以了.具体可以 ...

  8. 洛谷P1458 顺序的分数 Ordered Fractions

    P1458 顺序的分数 Ordered Fractions 151通过 203提交 题目提供者该用户不存在 标签USACO 难度普及- 提交  讨论  题解 最新讨论 暂时没有讨论 题目描述 输入一个 ...

  9. 华为OJ平台——将真分数分解为埃及分数

    题目描述: 分子为1的分数称为埃及分数.现输入一个真分数(分子比分母小的分数,叫做真分数),请将该分数分解为埃及分数.如:8/11 = 1/2+1/5+1/55+1/110. 输入: 输入一个真分数, ...

随机推荐

  1. Python练习题 016:猴子吃桃

    [Python练习题 016] 猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个.第二天早上又将剩下的桃子吃掉一半,又多吃了一个.以后每天早上都吃了前一天剩下的一半零一个.到 ...

  2. C++重载>>和<<(输入和输出运算符)详解

    转载:http://c.biancheng.net/view/2311.html 在C++中,标准库本身已经对左移运算符<<和右移运算符>>分别进行了重载,使其能够用于不同数据 ...

  3. 099 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 02 案例分析及实现 03 编写并测试Student类

    099 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 02 案例分析及实现 03 编写并测试Student类 本文知识点:编写并测试Subject类 说明: ...

  4. shell-的特殊变量-进程状态变量$$ $! $? $_详解

    一:shell的特殊变量-进程状态变量详解  1. 进程状态变量 $$ 获取当前shell的进程号(pid) $! 执行上一个指令的pid,上一个后台运行进程的进程号 $? 获取执行上一个指令的返回值 ...

  5. Python+Appium自动化测试(14)-yaml配置Desired capabilities

    一,前言 在之前的appium自动化测试示例中,我们都是把构造driver实例对象的数据(即Desired Capabilities)写在业务代码里,如下: # -*- coding:utf-8 -* ...

  6. 实验三 HTML表格和表单的制作

    实验三 HTML表格和表单的制作 [实验目的] 1.掌握表格的创建.结构调整与美化方法: 2.熟悉表格与单元格的主要属性及其设置方法: 3.掌握通过表格来进行网页页面的布局方法. [实验环境] 连接互 ...

  7. 两大IT培训巨头,达内和传智播客哪个更好?

    多年来,从财报收入及培训规模角度来看,达内和传智播客分别在IT培训领域占据第一和第二的位置已经是不争的事实,但是从培训学员的角度来讲,选择达内和传智播客哪个更好呢,这两家机构在学员心目中的排名和营收的 ...

  8. mac 解决安卓模拟器链接不上网络

    方法1.临时方法,每次启动都要加114.114.114.114 1.进入到下面的目录 /Users/anxiaodong/Library/Android/sdk/emulator 2.执行以下命令 e ...

  9. java List<T>和List<Object>的区别

    // List<T> 的T表示的是某一类型可以用人一类型来替代,一般在定义的时候使用 // List<Object> 就是具体的了表示这个List里只能放置Object pub ...

  10. T-sql语句,group by 加 order by的使用方法

    select AuHousesID,sum(Turnover) from Auction group by AuHousesID order by sum(Turnover) desc