题意:给出房间的宽度r和s个挂钩的重量。设计一个尽量宽,但宽度不超过房间宽度的天平,挂着所有的挂钩。挂钩的宽度不计,且不相同的挂钩可以互相重叠
思路:每次将当前集合分成两个不相交的子集合,每次都构造出子集的最大的天平,最后从子集中选出最大的
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int MAXN = 65; double r,w[10],value[MAXN],ans; struct node{ double l1,l2; }nw; vector<node> adj[MAXN]; int vis[MAXN],num[MAXN],n; void dfs(int state){ double l1,l2; bool flag = false; if (vis[state]) return; vis[state] = true; for (int i = (state&(state-1)); i > 0; i = ((i-1)&state)){ int j = state ^ i; dfs(i); dfs(j); for (int s = 0; s < num[i]; s++) for (int p = 0; p < num[j]; p++){ l1 = value[j] / (value[i]+value[j]); l2 = value[i] / (value[i]+value[j]); nw.l1 = max(adj[i][s].l1+l1,adj[j][p].l1-l2); nw.l2 = max(adj[i][s].l2-l1,adj[j][p].l2+l2); if (nw.l1 + nw.l2 <= r){ adj[state].push_back(nw); num[state]++; } } flag = true; } if (!flag){ nw.l1 = nw.l2 = 0; adj[state].push_back(nw); num[state]++; } } 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++){ adj[i].clear(); value[i] = 0; for (int j = 0; j < n; j++) if (i & (1<<j)) value[i] += w[j]; } memset(num,0,sizeof(num)); memset(vis,0,sizeof(vis)); dfs((1<<n)-1); ans = -1; for (int i = 0; i < num[(1<<n)-1]; i++){ if (adj[(1<<n)-1][i].l1 + adj[(1<<n)-1][i].l2 > ans) ans = adj[(1<<n)-1][i].l1 + adj[(1<<n)-1][i].l2; } printf("%.20f\n",ans); } return 0; }