uva12558 (迭代加深搜索)

来源:互联网 发布:合肥飞友网络怎么样 编辑:程序博客网 时间:2024/05/03 17:59

题目链接
题意:对一个分数(n/m)将它分解成若干个不相等的单分子分数(即分子为1)。求最少能分解成哪几个分数相加。若有多解,输出最大的分母尽量的小的解。会有k个禁止使用的单分子分数。
思路:这题搜索的特点就是深度和宽度都不确定,首先对于一个a/b,你不知道他的最优解有几个1/a类似形式的分数构成,这是宽度。对于每个1/i他的深度也是不确定的,唯一剪枝的条件就是确定深度后余下都选择1/i之和小于a/b。
详细过程见编码

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxn=100000+10;set<ll>ban;int maxed;bool ok;ll v[maxn],ans[maxn];ll gcd(ll a,ll b) {return b==0 ?  a : gcd(b,a%b);}//求两个数最大公约数ll get_first(ll a,ll b){return b/a+1;}//求比a/b小的最大的分子为一的分数bool better(int d){//判断当前解比答案更满足题意  for(int i=d;i>=0;i--){    if(ans[i]!=v[i]){        return ans[i]==-1||v[i]<ans[i];    }  }  return false;}void dfs(int cur,ll from,ll a, ll b){//当前深度为cur,起点from开始搜和为a/b的解    if(cur==maxed){        if(b%a||ban.count(b/a)) return;        v[cur]=b;        if(better(cur)) memcpy(ans,v,sizeof(ll)*(cur+1));        ok=true;        return;    }    from=max(from,get_first(a,b));    for(int i=from;;i++){       if(a*i>=b*(maxed-cur+1)) return;//如果剩下的解都是1/i还小于a/b那就说明不满足       if(ban.count(i)) continue;       v[cur]=i;       ll t1=a*i-b,t2=b*i;//约分求新的剩下       ll g=gcd(t1,t2);       dfs(cur+1,i+1,t1/g,t2/g);    }    return;}int main(){   int T,t=1;scanf("%d",&T);   while(T--){      ban.clear();      ll a,b;int n;      scanf("%lld %lld %d",&a,&b,&n);      for(int i=0;i<n;i++){         ll x;scanf("%lld",&x);ban.insert(x);      }      ok=false;      for(maxed=1;;maxed++){          memset(ans,-1,sizeof(ans));          dfs(0,get_first(a,b),a,b);          if(ok) break;      }      printf("Case %d: %lld/%lld=",t++,a,b);      printf("1/%lld",ans[0]);      for(int i=1;i<=maxed;i++) printf("+1/%lld",ans[i]);      puts("");   }}
0 0