1. 程式人生 > >UVA12558 Egyptian Fractions (HARD version)(埃及分數)

UVA12558 Egyptian Fractions (HARD version)(埃及分數)

names clear for 下界 rac algorithm bool .com scan

傳送門

題目大意

給出一個真分數 a/b,要求出幾個互不相同的埃及分數(從大到小),使得它們之和為 a/b

(埃及分數意思是分子為1的分數,詳見百度百科)

如果有多組解,則分數數量少的優先

如果分數數量一樣則分母最大的要盡量小,如果最大的分母同樣大,則第二大的分母盡量小,以此類推

為了加大難度,會給出k個不能作為分母的數

(2<=a,b<=876,k<=5 並且 a,b 互質)

首先想的是數論,但是呢

推不出來...

然後發現a,b好像不大

貌似可以搜索

但是呢

不知道上界...

那就叠代加深搜索唄

然後想想怎麽剪枝

如果知道 a/b,要怎麽求出最小 k 使 1/k < a/b 呢(註意符號)

易知 a/b 為真分數 ,a,b,k均為整數
所以 a<b
所以必定有整數 x,y 使得 x*a+y=b 且y<a
所以可得 int(b/a)=int( (x*a+y) /a )=int(x*a/a)+int(y/a) = x
因為 int(b/a)<=b/a,int(b/a)=x
所以 int(b/a)+1>b/a,x+1 > b/a
所以1/(x+1) < a/b
又 1/int(b/a)=1/x >=a/b
所以 x+1就是最小的 k 使得 1/k < a/b
所以 k=int(b/a) + 1

證明完畢

知道了 k 的下界,那還要求 k 的上界

顯然每次求的分母肯定要比上一次大(題目要求)

所以如果後面所有的分母都為 k ,加起來還沒有當前要求的數大,那就不要再搜下去了,再下去也不會有結果的

然後就可以搜了,至於判斷是否可用我用的是set

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
using namespace std;
const int N=1e5+7;
set <long
long> p; long long t,A,B,n,mxdep; long long ans[N],w[N]; bool flag; inline long long gcd(long long a,long long b) { return b ? gcd(b,a%b) : a; }//gcd是為了約分 inline bool pd() { for(int i=mxdep;i;i--) if(ans[i]!=w[i]) return ans[i]&&ans[i]<w[i]; return 0; }//判斷答案是否更優 inline void dfs(long long dep,long long a,long long b,long long mi) { if(dep==mxdep) { if(b%a||(b<(mi-1)*a+1)||p.count(b/a)) return;//判斷合法性 //如果a/b可化為 1/k 的形式並且 1/k 可以選 w[dep]=b/a; if(pd()) return;//判斷答案是否更優 memcpy(ans,w,sizeof(w)); flag=1;//更新 return; } mi=max(mi,b/a+1);//求出下界 for(long long i=mi;i;i++) { if( (mxdep-dep+1)*b<=i*a ) return;//上界 if(p.count(i)) continue;//判斷合法 w[dep]=i;//記錄路徑 long long xa=a*i-b,xb=i*b;//通分 long long z=gcd(xa,xb); dfs(dep+1,xa/z,xb/z,i+1);//約分,向下一層 } } int main() { cin>>t; for(long long i=1;i<=t;i++) { flag=0; mxdep=1; cin>>A>>B>>n; long long c; p.clear();//細節 while(n--) scanf("%lld",&c),p.insert(c);//存儲不合法的數 while(mxdep++) { memset(ans,0,sizeof(ans)); dfs(1,A,B,B/A+1); if(flag) break; }//叠代加深 printf("Case %lld: %lld/%lld=1/%lld",i,A,B,ans[1]); for(int i=2;i<=mxdep;i++) printf("+1/%lld",ans[i]); printf("\n"); } return 0; }

UVA12558 Egyptian Fractions (HARD version)(埃及分數)