UVA 12558 埃及分数 Egyptian Fractions (HARD version)

UVA 12558 埃及分数 Egyptian Fractions (HARD version)

UVA12558

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.

Input

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.

Output

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:

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

Sample Input

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

Sample Output

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

这是一道经典的迭代加深搜索提,为什么要用迭代加深搜索,首先若是直接dfs, 但是我们不知道到底会有多少项,因此时间复杂度会十分的高,从而,我们可以先确定dfs搜索的深度,然后根据深度,再逐级开始搜索,从而这道题就迎刃而解了。话不多说直接上代码:

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
ll temp[1000];
vector<ll> answer;
int num[300];
ll gcd(ll a,ll b){
    return a%b == 0 ? b : gcd(b,a%b);
}
ll lcm(ll a,ll b){
    return a*b/gcd(a,b);
}

class Fraction{
    public:
        Fraction(ll numerator,ll denominator):numerator(numerator),denominator(denominator){};
        ll numerator;
        ll denominator;
        Fraction operator - (const Fraction& f1) const{
            ll denominatorNow = lcm(this->denominator,f1.denominator);
            ll numeratorNow = denominatorNow/this->denominator*this->numerator - denominatorNow/f1.denominator*f1.numerator;
            return Fraction(numeratorNow,denominatorNow); 
        }
        friend ostream& operator << (ostream &out, const Fraction& f1){
            out<<f1.numerator<<'/'<<f1.denominator;
            return out;
        }
};
Fraction reduction(Fraction f1){
    int gcd1=gcd(f1.numerator,f1.denominator);
    if(gcd1==1)
        return f1;
    else
        return Fraction(f1.numerator/gcd1,f1.denominator/gcd1);
}
bool check(int number,int k){
    for(int i=1;i<=k;i++){
        if(number==num[i]){
            return true;
        }
    }
    return false;
}
bool dfs(Fraction f1,ll start,int k,int node,int max1){
    if(node==max1){
        if(f1.numerator!=1 || f1.denominator<=temp[node-1] || check(f1.denominator,k))
            return false;
        temp[node]=f1.denominator;
        if(answer.size()<max1+1){
            for(int i=0;i<=max1;i++){
                answer.emplace_back(temp[i]);
            }
            return true;
        }
        for(int i=max1;i>=0;i--){
            if(answer[i]>temp[i]){
                for(int j=0;j<=max1;j++){
                    answer[j]=temp[j];
                }
                break;
            }
            else if(answer[i]<temp[i])
            {
                break;
            }
                
        }
        return true;
    }
    bool flag=false;
    ll begin=max(f1.denominator/f1.numerator+1,start);
    for(ll i=begin;;i++){
        if(f1.numerator*i>f1.denominator*(max1-node+1))
            break;
        if(check(i,k)){
            continue;
        }
        temp[node]=i;
        Fraction now = f1 - Fraction(1,i); 
        now=reduction(now);
        if(dfs(now,i+1,k,node+1,max1))
            flag=true;
    }
    return flag;

}
int main(){
    int t;
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin>>t;
    int cnt=1;
    while(t--){
        answer.clear();
        ll a,b,k;
        cin>>a>>b>>k;
        for(int i=1;i<=k;i++){
            cin>>num[i];
        }
        Fraction fraction1=Fraction(a,b);
        for(int i=1;;i++){
            if(dfs(fraction1,0,k,0,i))
                break;
        }
        cout<<"Case "<<cnt++<<": "<<fraction1<<"=";
        for(auto it=answer.begin(); it!=answer.end();it++){
            if(it==answer.begin()){
                cout<<Fraction(1,*it);
            }
            else{
                cout<<"+"<<Fraction(1,*it);
            }
        }
        cout<<endl;
    }
    //getchar();
    //getchar();
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值