uva12558(埃及分数--难)(IDDFS入门题)

迭代深搜(IDDFS),顾名思义就搜索深度一次增加一的深度优先搜索,这样就能达到与广度优先搜索类似的效果。但是广搜的空间复杂度太高,迭代深搜就能很好地弥补这点。
写法和深搜差不多,就是加了一个深度。当当前搜索深度大于限定时就退出。
另外,对于这道题每给一个深度(也就是选择几项分数),每次选一个分数时它的分母是有范围限制的,
首先它要大于上一个分数的分母,
然后它还要大于等于(la+lb-1)/la向下取整,这个比较难理解
本来应该满足的是1/s<=la/lb==》s>=lb/(double)la,但是由于lb/la是向下取整,可能lb/la实际上是不可以选的,所以就s>=(la+lb-1)/la;剪枝更彻底。比如(a/b=2/3,3/2=1,但其实1不可以选,但(2+3-1)/2等于2,1就被跳过了)
也就是s>=(la+lb-1)/la向下取整,即1/s<=la/(lb+la-1),
1/s<=1/(1+(lb-1)/la)
s<=INF/y,是防止爆int,
s<=(mcr-cur)*lb/la,这个就比较明显吧,现在还需要选mur-cur项
,而每一项分母递增,(以后能选的最大值)(mcr-cur)*1/s>=la/lb。

/*310ms*/
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <stack>
#include <vector>
#include <string.h>
#include <queue>
#define msc(X) memset(X,-1,sizeof(X))
#define ms(X) memset(X,0,sizeof(X))
typedef long long LL;
using namespace std;
const int INF=0x7fffffff;
int gcd(int a,int b)
{return b?gcd(b,a%b):a;}
int arr[8],k,res[19000],tmp[19000];
bool IDDFS(int cur,int mcr,int a,int b,int lt)
{
    if(cur>=mcr-1){
        if(a!=1||b<lt) return false;
        for(int j=0;j<k;j++) if(arr[j]==b) return false;
        tmp[cur]=b;
        bool flg=false;
        if(res[0]){
            for(int i=cur;i>-1;i--)
                if(res[i]!=tmp[i]){flg=(res[i]>tmp[i]);break;}
        }
        if(res[0]==0||flg)
        memcpy(res,tmp,sizeof(tmp));
        return true;
    }
    if(!a) return false;
    lt=max(lt,(a+b-1)/a);
    bool flg=false;
    for(int i=lt;i<=INF/b&&i<=(mcr-cur)*b/a;i++)//i<=INF/b关键的一步,否则wa
    {
        bool Is_s=true;
        for(int j=0;j<k;j++) if(i==arr[j]) {
            Is_s=false;
            break;
        }
        if(!Is_s) continue;
        int na=a*i-b,nb=b*i;
        if(na<0) continue;
        tmp[cur]=i;
        int g=gcd(na,nb);
        na/=g,nb/=g;
        flg=IDDFS(cur+1,mcr,na,nb,i+1)||flg;
    }
    return flg;
}
int main(int argc, char const *argv[])
{
    int t,ti=0;
    scanf("%d",&t);
    while(++ti<=t){
        int a,b;
        scanf("%d %d %d",&a,&b,&k);
        for(int i=0;i<k;i++) scanf("%d",arr+i);
        int mcr=1;
        ms(res);
        while(1)
            if(IDDFS(0,mcr,a,b,2))  break;
            else mcr++;
        printf("Case %d: %d/%d=1/%d",ti,a,b,res[0] );
        for(int i=1;i<mcr;i++)
            printf("+1/%d", res[i]);
        putchar('\n');
    }
    return 0;
}
/*
5
2 3 0
19 45 0
2 3 1 2
5 121 0
5 121 1 33

6
596 829 0
265 743 0
181 797 0
616 863 0
22 811 0
732 733 0
//最后一个错了是因为数的范围太小,全部改为long long就
//都对了,但是这道题不改long long也能过judge,所以就没改了,
//改了时间会变大
下面是这一部分数据(输入是1   732 733 0)
当计算到tmp[0]=2,tmp[1]=3,tmp[2]=7,tmp[3]=45时
a=103,b=461790
接着算下一层时i
从4484开始枚举,到4650停止,因为后面i>4650时
i>INF/y.被剪掉了=。=
*/
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值