codevs 1288 埃及分數
阿新 • • 發佈:2019-01-23
題目大意:給出一個分數,要求求出最少的x分之1的形式,如果個數相同,要求最小的數字最大。
考慮搜尋,因為總個數不確定,使用IDDFS,每次確定一個長度,對於每一個位置從可以成立的最小值開始列舉。
對於最終情況:如果這次的a為1,並且b比前面的一次大,那麼就是最終情況,這時如果這個長度沒出現過,那麼當前序列
作為答案,如果出現過,那麼選擇最大的最後一位作為答案。
對於搜尋,每一次的新值的最小值一定要比當前的b/a大,這樣1/i就比a/b大,同時也要比上一個選擇i要大,因為我們選擇的
答案是遞增的。對於最大值,極限情況就是後續都選擇i時,整體要比a/b大,所以i<(now-dep+1)*b/a。
如果最大值大於int要縮成int的極限值-1(玄學優化。。。),如果這個長度已經有過答案了,那麼極限值要比目前答案的最小值
大,這樣才有意義。傳入下一層的就是a/b-1/i的對應分子和分母。
#include<cstdio> #include<cmath> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; ll a,b,ans[15],tmp[15],now,inf=2147483647; ll gcd(ll x,ll y) { if(y==0)return x; return gcd(y,x%y); } int flag; void dfs(ll dep,ll na,ll nb) { if(dep>now)return;//這個地方也可以和下面的判斷寫在一起,當然瞭如果有最優答案早就結束了 if(na==1&&nb>tmp[dep-1]) { tmp[dep]=nb; if(!flag||tmp[dep]<ans[dep]) { memcpy(ans,tmp,sizeof(tmp)); } flag=1;return; } ll st=max(nb/na,tmp[dep-1]+1),ed=(now-dep+1)*nb/na; if(ed>inf)ed=inf-1; if(flag&&ed>=ans[now])ed=ans[now]-1; for(ll i=st;i<=ed;i++) { tmp[dep]=i; ll ty=gcd(na*i-nb,nb*i); dfs(dep+1,(na*i-nb)/ty,nb*i/ty); } } int main() { scanf("%lld%lld",&a,&b); ll c=gcd(a,b); a/=c,b/=c; if(a==1) { printf("%lld\n",b); return 0; } tmp[0]=1; for(now=1;;now++) { dfs(1,a,b); if(flag) { for(int i=1;i<=now;i++) { printf("%lld ",ans[i]); } return 0; } } return 0; }