题意:给你一个房间的宽度和n个挂坠的重量,在满足力矩平衡的条件下,问挂完这些挂坠不超过房间宽度的最长木棍长度之和是多少。注:每根木棍长度为一,且两端只能悬挂挂坠或者另一个木棍,这里的木棍不能水平拼接!只能单独使用!
思路:因题目数据小,所以 - 〉枚举二叉树,由小树一步步合并为大树,从顶部向下回溯,有点区间dp的感觉
收获技巧:
1.位运算如何枚举二叉树?
我们用二进制对应i位上表示这个子树挂不挂第i个挂坠,然后枚举这个二进制的所有子集为左子树,那么他的对称差集就是右子树,然后构成这棵子树的不同树形,每一种合格的树形都存在tree[这个二进制集合]里,那么同理,最后tree[全集]存的就是挂坠全挂上的时候的所有树形,这时候只要枚举每一个树形的lift+right长度,取最大的即可!
2.对于每一棵子树怎么求他的长度?
tree[father].L = l2+ l1(而l是与一侧挂坠与总重的比例)同理右侧
tree[father].L = l3 - r1
所以要综合判断: t.L = max(tree[lefted][i].L+lf,tree[righted][j].L-lr);
t.R = max(tree[righted][j].R+lr,tree[lefted][i].R-lf);
3.如何枚举子集?
for(int lefted = (father-1)&father;lefted;lefted = (lefted-1)&father)
int righted = father^lefted;构造差集
代码:
#include <iostream> #include<bits/stdc++.h> using namespace std; double r; int n; struct Tree { double L,R; Tree(double a = 0,double b = 0):L(a),R(b) {} }; double w[6]; double sum[150]; bool vis[150]; vector<Tree> tree[150]; void dfs(int father){ if(vis[father])return; vis[father] = 1;//剪枝,已经判断了的直接结束 bool judge = false;//是否有子集 for(int lefted = (father-1)&father;lefted;lefted = (lefted-1)&father)//枚举子集 { judge = true; int righted = father^lefted;//取差集 double lf = sum[righted]/sum[father];//左子集在father杆的左侧长度 double lr = sum[lefted]/sum[father];//右子集在father杆的右侧长度 dfs(righted); dfs(lefted);//下面构造father树下所有可能的由左右子集构成的树形 for(int i = 0;i<tree[lefted].size();i++){//左子树的树形 for(int j = 0;j<tree[righted].size();j++){//右字树所有可能的树形 Tree t;//构造father其中一个树形 t.L = max(tree[lefted][i].L+lf,tree[righted][j].L-lr);//判断长度,取最大 t.R = max(tree[righted][j].R+lr,tree[lefted][i].R-lf); if(t.L+t.R<r)tree[father].push_back(t); } } } if(!judge) tree[father].push_back(Tree(0,0)); } int main() { int T; scanf("%d",&T); while(T--){ scanf("%lf%d",&r,&n); memset(vis,0,sizeof(vis)); memset(sum,0,sizeof(sum)); for(int i = 0;i<n;i++){ scanf("%d",&w[i]); } int root = (1<<n) - 1; for(int i = 0;i<=root;i++){ tree[i].clear(); for(int j = 0;j<n;j++){ if(i&(1<<j))sum[i]+=w[j];//所有子集总重量 } } 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; }