UVA1354 Mobile Computing
阿新 • • 發佈:2018-12-23
做法有兩種,一種是從頂向下構造解答樹。
第二種,從下向上構造解答樹。
本題解析採用自頂向下,每次列舉左子樹用到的子集,則右子樹就是剩下的子集。科普子集
#include<cstdio> #include<vector> #include<cstring> using namespace std; const int maxn = 6; struct Tree{ double L, R; Tree():L(0), R(0){} }; vector<Tree> tree[1<<maxn]; double w[maxn], sum[1<<maxn], r; int n, vis[1<<maxn]; void dfs(int subset){ if(vis[subset]) return; vis[subset] = true; int haveChildren = false; for(int left = subset & (subset - 1); left; left = (subset) & (left - 1)){ haveChildren = true; int right = subset^left; double d1 = sum[right] / sum[subset]; double d2 = sum[left] / sum[subset]; dfs(left); dfs(right); for(int i = 0; i < tree[left].size(); ++i){ for(int j = 0; j < tree[right].size(); ++j){ Tree t; t.L = max(tree[left][i].L + d1, tree[right][j].L - d2); t.R = max(tree[left][i].R - d1, tree[right][j].R + d2); if(t.L + t.R < r) tree[subset].push_back(t); } } } if(!haveChildren) tree[subset].push_back(Tree()); } int main(){ int T; scanf("%d", &T); while(T--){ scanf("%lf%d", &r, &n); for(int i = 0; i < n; ++i) scanf("%lf", &w[i]); for(int i = 0; i < (1 << n); ++i){ sum[i] = 0; tree[i].clear(); for(int j = 0; j < n; ++j){ if(i & (1 << j)) sum[i] += w[j]; } } int root = (1<<n)-1; memset(vis, 0, sizeof(vis)); dfs(root); double ans = -1; for(int i = 0; i < tree[root].size(); i++) ans = max(ans, tree[root][i].L + tree[root][i].R); printf("%.10lf\n", ans); } return 0; }