uva 12558 Egyptian Fractions (HARD version)

此题就是在原始的埃及分数上添加了一个条件,就是在解中限制了不能包含的一些数。

算法为IDA*算法,还是比较容易理解的

//
//  main.cpp
//  埃及分数
//
//  Created by XD on 15/7/28.
//  Copyright (c) 2015年 XD. All rights reserved.
//



#include <iostream>
#include <string>
#include <queue>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include<vector>
#include <string.h>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <cstdio>
#define  ll long long
using namespace std ;

set<ll > s ;
ll v[110] ;
ll ans[110] ;
int maxn ;

//欧几里得算法
ll gcd(ll a , ll b)
{
    return b == 0 ?a : gcd(b,a%b) ;
}

ll max(int a , ll b)
{
    return a  >b ? a : b ;
}

//获得第一个分数的分母  即找到c使得 1/c <= a / b
ll get_first(ll a , ll b )
{
    ll c   ;
    c = b / a  ;
    if (b%a) {
        c+= 1 ;
    }
    return  c ;
}
//判断当前的答案是否比以前的答案更好   ans[i] ==-1 是初始状态下
bool better(ll d)
{
//    for (ll i = d ; i>= 0; i--) {
//        
//        if (ans[i] != v[i] ) {
//            return ans[i]==-1 || ans[i] > v[i] ;
//        }
//    }
    for (ll i = d ; i>= 0; i--) {
        
        if (ans[i] != v[i] ) {
            return ans[i]==-1 || ans[i] > v[i] ;
        }
    }
    return false ;
}

//当前的深度是d ,开始的分母的值最小为from  余下的和为aa / bb

bool dfs(ll d , ll from ,ll aa , ll bb)
{
    if (d == maxn  ) {
        if (bb % aa) {
            return false ;
        }
        v[d] = bb /aa ;
        if(s.count(bb/aa)) return false;
        if (better(d)) {
            memcpy(ans, v, sizeof(ll) * (d + 1));
        }
        return true ;
    }
    bool ok = false ;
    from = max(from , get_first(aa, bb)) ;
    for (ll i = from ; ; i++) {
        //剪枝--这个剪枝相当重要,没有的画程序会一直跑,而没有结果。原因是程序不知道后面的i不会产生我们想要的结果
        
        if (s.count(i)) {
            continue ;
        }
        if(bb *  (maxn -d + 1) <= i *aa)
        { break ;}
        v[d] = i ;
        ll b2 = bb * i  ;
        ll a2 = aa * i - bb ;
        ll g = gcd(a2 , b2) ;
        if (dfs(d + 1, i + 1, a2/g, b2/g)) {
            ok = true ;
        }
    }
    return  ok ;
}


int main() {
    
    ll a , b ;
    int casenum ;
    scanf("%d" ,&casenum) ;
    int j = 0 ;
    while (casenum--) {
       
        scanf("%lld%lld" , &a , &b) ;
        int k,d  ;
        scanf("%d" ,&k) ;
        s.clear() ;
        for (int i = 0; i  <  k ; i++) {
            scanf("%d" ,&d) ;
            s.insert(d) ;
        }
        int  ok = 0 ;
        for (maxn = 1;  ; maxn++) {
            memset(ans, -1, sizeof(ans)) ;
            if (dfs(0, get_first(a, b), a, b)) {
                ok = 1 ;
                break ;
            }
        } printf("Case %d: ",++j) ;
        printf("%lld/%lld=" , a,  b ) ;
        int i  = 0 ;
        for ( i = 0; ; i++) {
            if (ans[i+1] == -1) {
                break ;
            }
            else{
                printf("1/%lld+" , ans[i]);
            }
        }
        printf("1/%lld\n" ,ans[i]) ;
        
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值