1. 程式人生 > >uva12558(埃及分數--難)(IDDFS入門題)

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.被剪掉了=。= */