题目提交点
解题思路
这个题目数据范围有点小, 我刚开始想的是用dfs, 可是遇到了一些问题, 不知道他什么时候结束,最优解有几项,新加入的埃及分数取什么值最好等等问题困惑着我。
顺着理一下思路,需要暴力做这题,但是不知道上限,非常符合迭代加深搜的算法规则,OK,开始分析细节。
①迭代加深搜,搜到了就结束,没搜到就继续搜, dfs层数代表着埃及分数的项数。
②dfs剪枝, 层数超过了,或者累加的答案已经超过所要的答案了,进行剪枝操作。
③对埃及分数取值问题:
a, b 分别为已经累加到的数分子与分母,A, B分别为所需要的分子与分母。
设1/c 为所加的埃及分数, 便有
1/c + a / b <= A / B
==> 1/c <= A/B - a/b = (Ab - aB)/Bb
==> c >= Bb/(Ab - aB)
再与上一个已经取的值做比较,取最大,那么这个数就是最小的c值。
不一定这个最小的值是最好的,所以得不断的尝试, 让这个值自加。
设no 为最小的c的取值,max_d 为此dfs最大能到的层数, d 为当前层数。
当这个新取的埃及分数小到无论怎么取都达不到的值时,结束此埃及分数的取值,即 a/b + (max_d - d) / no < A / B
。
代码
#include<bits/stdc++.h>
#include<unordered_set>
using namespace std;
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
typedef long long LL;
int A, B;
unordered_set<LL> R;
inline int readint()
{
int x;
scanf("%d", &x);
return x;
}
LL gcd(LL a, LL b)
{
return b ? gcd(b, a % b) : a;
}
LL get_first(LL a, LL b, LL last)
{
return max((B * b) / (A * b - a * B), last + 1);
}
bool judge(const vector<LL>& D, const vector<LL>& ans)
{
if (ans.empty()) return true;
for (int i = ans.size() - 1; ~i; --i) if (D[i] != ans[i])
return D[i] < ans[i];
return false;
}
void dfs(LL a, LL b, const int d, const int max_d, vector<LL>& D, vector<LL>& ans)
{
if (d > max_d) return;
if (a * B > A * b) return;
if (a == A && b == B)
{
if (judge(D, ans)) ans = D;
return;
}
LL no = get_first(a, b, D.empty() ? 1LL : D.back());
while (true)
{
if (a * B * no + (max_d - d) * B * b < A * b * no) break;
if (!R.count(no))
{
LL na = a * no + b, nb = b * no, g = gcd(na, nb);
D.push_back(no);
dfs(na / g, nb / g, d + 1, max_d, D, ans);
D.pop_back();
}
no++;
}
}
int main()
{
#ifdef LOCAL
freopen("data.in", "r", stdin);
#endif
int T = readint();
_rep(kase, 1, T)
{
A = readint(), B = readint();
int k = readint();
R.clear();
_for(i, 0, k) R.insert(readint() * 1LL);
for (int d = 2; ; ++d) {
vector<LL> D, ans;
dfs(0, 1, 0, d, D, ans);
if (!ans.empty()) {
printf("Case %d: %d/%d=", kase, A, B);
int sz = ans.size();
_for(i, 0, sz)printf("1/%lld%s", ans[i], (i == sz - 1) ? "\n" : "+");
break;
}
}
}
return 0;
}