题目
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;
}