题目
http://codevs.cn/problem/1288/
卧槽。整了一天还是没全 AC 后面多层的时候不知道问题出在哪里了,跑不出来。
这个题的难点在于解答树的每一层都是无穷多,这导致我们必须要强烈的剪枝!否则绝对没有办法跑完。由于题目的特殊性(拆分),所以我们要尽量剪枝,估计是因为我这个剪的还不够,一到难题就不行了。还有3/997 算不出来的原因有点特别。以后再仔细想想。
#include <iostream> using namespace std; int res[10]={0};//用来存储临时结果 int depth =2;//用来存储现行深度 int last_min = 1<<30;//用来选取最优的埃及分数最后一项 int final_res[10]={0};//用来存储最优埃及分数 bool ok = false;//用来判断是否是合格的深度 //找最大公因数 int findGCD(int a,int n){ if(a==0) return 1; if(n%a==0) return a; for(int i=2;i<a;i++){ if(a%i==0 and n%i==0) return i; } return 1; } //找最小公倍数 int findLCM(int a,int n){ if(n%a==0) return n; int gcd = findGCD(a,n); //16 24 gcd = 8 lcm = 8*2*3 return a*n/gcd; } //深度搜索 cur 是光标 m,n 分别是当前要解决的分子分母 void dfs(int cur,int cur_m,int cur_n){ //如果cur 到了最后了 if(cur==depth){ //如果此时分子是0 表示我们找到了一组埃及分数 //此时如果最后一个分母比已经记录的要小 我们就要更新了 if(cur_m==0 and res[cur-1]<last_min){ ok = true;//表示此深度是合格的 //得到了结果~~比较之后存储一下 last_min = res[cur-1];//更新最小 for(int i=0;i<depth;i++) final_res[i]=res[i]; } return; } if(cur_n==0 or cur_m==0) return; //1/a 必须要小于 m/n 才行!为了加快速度让 a 直接是 n/m for(int a=cur_n/cur_m;;a++)if(a*cur_m>=cur_n){ //这层剪枝是这样的:如果是该埃及分数序列的第一位 //且发现 深度*第一位 还比 m/n 小 那就没必要开始了 if(cur==0 and depth*cur_n<=a*cur_m) return; //接着要进行减法运算 int lcm = findLCM(a, cur_n);//通分之后的分母 int lcm_1 = lcm/a; int lcm_m = cur_m*lcm/cur_n; int sub = lcm_m-lcm_1;//通分之后做差 int gcd = findGCD(sub,lcm); if(gcd!=1){sub /= gcd;lcm/=gcd;}//化简结果 if((depth-cur-1)>0 and (depth-cur-1)*lcm<sub*(a+1)){ //此时要检查有没有继续遍历的必要 //现在还剩 depth-cur-1个位置没有填 如果发现即使都填1/(a+1) //之后也无法填满还剩的部分,所以就减掉 //剪枝 return; } res[cur]= a;//如果都合适,那就存进去 dfs(cur+1,sub,lcm);//继续搞 if(cur+1==depth)//如果已经到了结尾 就手动结束 //这一步比较特别 以前没考虑过这样的地方 这可能是因为无穷的原因 return; } return; }