您的位置:首页 > 其它

UVA12558->IDDFS

2016-07-23 12:54 316 查看
题意:给出一个真分数,把它分解成最少的埃及分数的和。同时给出了k个数,不能作为分母出现,要求解的最小的分数的分母尽量大。

题解:IDDFS(Iterative-Deepening Depth First Search)在搜索解答树时,每次只考虑深度不超过maxd的结点,当搜索深度超过maxd时直接回溯,然后逐步增大maxd的值。这样就可以很好的解决解答树的深度过深的问题——因为我要的解状态的深度一定是有限的

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
typedef long long LL;
const int maxn=10010;
int maxd,t,tt;
set<LL> sk;
LL ans[maxn],v[maxn];
LL gcd(LL a,LL b)
{
return b?gcd(b,a%b):a;
}
LL get_first(LL a,LL b)//得到满足1/c <= a/b 的最小c
{
return b/a+1;
}
bool better(int d)//判断当前的解是否为最优解
{
for(int i=d;i>=0;--i)
if(v[i]!=ans[i]) return ans[i]==-1||v[i]<ans[i];
return false;
}
//d代表当前搜索到第几层,from为该层符合条件的最大正整数,
bool dfs(int d,LL from,LL a,LL b)
{
if(d==maxd)// 最后一层时要求a/b是埃及分数
{
if(b%a) return false;
v[d]=b/a;
if(sk.count(b/a)) return false;//筛掉禁止使用的字符
if(better(d)) memcpy(ans,v,sizeof(LL)*(d+1));
return true;
}
bool ok=false;
for(LL i=max(from,get_first(a,b));;++i)
{
//剪枝,如果剩下的maxd+1-d个分数全为1/i,加起来仍小于a/b,无解
if(b*(maxd+1-d)<=i*a) break;
if(sk.count(i)) continue;
v[d]=i;
//计算a/b - 1/i ,设结果为a2/b2
LL b2=b*i;
LL a2=a*i-b;
LL g=gcd(a2,b2);
if(dfs(d+1,i+1,a2/g,b2/g)) ok=true;
}
return ok;
}
int main(){
scanf("%d",&t);
while(t--){
LL a,b,k,sk0;
sk.clear();
scanf("%lld%lld%lld",&a,&b,&k);
while(k--) scanf("%lld",&sk0),sk.insert(sk0);
for(maxd=0;;++maxd){
memset(ans,-1,sizeof(ans));
if(dfs(0,get_first(a,b),a,b)) break;
}
printf("Case %d: %lld/%lld=",++tt,a,b);
for(int i=0;i<=maxd;++i){
if(i) printf("+");
printf("1/%lld",ans[i]);
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: