uva12558 (迭代加深搜索)

题目链接
题意:对一个分数(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("");
   }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值