二叉树枚举,思路很简单,但枚举有技巧
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
#include<math.h>
#include<string>
#include<string.h>
#include<map>
#include<unordered_map>
#include<unordered_set>
#include<set>
#include<stack>
#include<sstream>
using namespace std;
const int maxn = 1 << 6;
int n;
double s, w[maxn],vis[maxn],sum[maxn];
struct tree {
double l, r;
tree() :l(0), r(0) {};
};
vector<tree> ans[maxn];
void dfs(int cur) {
if (vis[cur])
return;
vis[cur] = 1;
int has_children = 0;
for (int left = (cur - 1)&cur; left; left = (left - 1)&cur) {
has_children = 1;
int right = cur ^ left;
double d1 = sum[right] / sum[cur];
double d2 = sum[left] / sum[cur];
dfs(left);
dfs(right);
tree t;
for (int i = 0; i < ans[left].size(); i++) {
for (int j = 0; j < ans[right].size(); j++) {
t.l = max(ans[left][i].l + d1, ans[right][j].l - d2);
t.r = max(ans[right][j].r + d2, ans[left][i].r - d1);
if (t.l + t.r < s) ans[cur].push_back(t);
}
}
}
if (!has_children) ans[cur].push_back(tree());
}
int main() {
int t;
cin >> t;
while (t--) {
cin >> s;
cin >> n;
for (int i = 0; i < n; i++)
cin >> w[i];
for (int i = 0; i < (1 << n); i++) {
ans[i].clear();
vis[i] = 0;
sum[i] = 0;
for (int j = 0; j < n; j++) {
if (i & 1 << j)
sum[i] += w[j];
}
}
dfs((1 << n) - 1);
int m = 0;
double width = -1;
for (int i = 0; i < ans[(1 << n) - 1].size(); i++) {
width = max(width, ans[(1 << n) - 1][i].l + ans[(1 << n) - 1][i].r);
}
printf("%.9lf\n", width);
}
return 0;
}