【题意】给出了房间的宽度,天平长度为1,天平有左右两个空位,可以放重物或另一个天平,然后有n个重物放到天平上保持天平平衡的情况下问天平最宽延伸是多少。
【解题方法】 这道题十分的有意思,实在不知道怎么做,看了紫书的思路,仍然写不出代码,主要是不知道如何去枚举二叉树。查看了刘老师的标程,终于弄懂了、也学到了二叉树该如何去枚举。解决了这个问题就可以,每次枚举两个坠合并成一个坠,那么每次都会使得整个可选的坠的数目减一。
把每个坠都看成一个天平,因此有三个量需要维护:w,l,r(重量,左臂总长,右臂总长),同时在合并两个坠的时候要考虑特殊情况,左边的那个坠右臂特别长,或者右边的那个坠左臂特别长 。所以有这么一段:llx=max(a[i].l+l,a[j].l-r); rrx=max(a[j].r+r,a[i].r-l); 为了便于来理解我画一个图:
【AC代码】
//
//Created by BLUEBUFF 2016/1/6
//Copyright (c) 2016 BLUEBUFF.All Rights Reserved
//
#pragma comment(linker,"/STACK:102400000,102400000")
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <time.h>
#include <cstdlib>
#include <cstring>
#include <sstream> //isstringstream
#include <iostream>
#include <algorithm>
using namespace std;
//using namespace __gnu_pbds;
typedef long long LL;
typedef pair<int, LL> pp;
#define REP1(i, a, b) for(int i = a; i < b; i++)
#define REP2(i, a, b) for(int i = a; i <= b; i++)
#define REP3(i, a, b) for(int i = a; i >= b; i--)
#define CLR(a, b) memset(a, b, sizeof(a))
#define MP(x, y) make_pair(x,y)
const int maxn = 6;
const int maxm = 2e5;
const int maxs = 10;
const int maxp = 1e3 + 10;
const int INF = 1e9;
const int UNF = -1e9;
const int mod = 1e9 + 7;
int gcd(int x, int y) {return y == 0 ? x : gcd(y, x % y);}
//typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>order_set;
//head
struct node{
double l, r;
node(){}
node(int l, int r) : l(l), r(r) {}
};
int n, vis[1<<maxn];
double rr, w[maxn], sum[1<<maxn];
vector <node> tree[1<<maxn];
void dfs(int s)
{
if(vis[s]) return; //记忆化
vis[s] = 1;
bool leaf = 0;
for(int l = s & (s - 1); l; l = (l - 1) & s){//枚举二叉树
leaf = 1;
int r = s ^ l;
double d1 = sum[r] / sum[s];
double d2 = sum[l] / sum[s];
dfs(l);
dfs(r);
for(int i = 0; i < tree[l].size(); i++){
for(int j = 0; j < tree[r].size(); j++){
node tx;
tx.l = max(tree[l][i].l + d1, tree[r][j].l - d2);
tx.r = max(tree[r][j].r + d2, tree[l][i].r - d1);
if((tx.l + tx.r) < rr) tree[s].push_back(tx);
}
}
}
if(!leaf) tree[s].push_back(node(0, 0));
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%lf%d", &rr, &n);
REP1(i, 0, n) scanf("%lf", &w[i]);
REP1(i, 0, (1 << n)){
sum[i] = 0;
tree[i].clear();
REP1(j, 0, n){
if(i & (1<<j)){
sum[i] += w[j];
}
}
}
memset(vis, false, sizeof(vis));
int u = (1 << n) - 1;
dfs(u);
double ans = -1.0;
REP1(i, 0, tree[u].size()){
ans = max(ans, tree[u][i].l + tree[u][i].r);
}
printf("%.10f\n", ans);
}
return 0;
}