uva12558(埃及分數--難)(IDDFS入門題)
阿新 • • 發佈:2019-01-25
迭代深搜(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.被剪掉了=。=
*/