您的位置:首页 > 其它

UVA1354 (枚举二叉树)

2017-04-26 19:36 281 查看
给出房间的宽度,以及n个重物的重量,每个杆的长度为1,要求如图放置的宽度尽量宽但又不超过房间的宽度。输出保留10为小数即可。

枚举二叉树

需用第九章的枚举子集高速算法重做一遍

#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 6;

int vis[1 << maxn];
double r, w[1 << maxn];

struct Tree
{
double L, R;
Tree():L(0), R(0) {}
};

vector<Tree> tree[1 << maxn];//每棵子树的属性有左右长度、包含结点以及重量。以包含结点的二分配为节点(每个节点可代表多种子树)建立新树。其中包含结点以二进制集合用作节点标号;包含结点所能组成的所有可能二叉树左右长度用结构体vector表示为节点特有属性,递归求解,dfs目的;重量只与包含结点有关,不必递归处理,用数组存储

void dfs(int subset)
{
if (vis[subset])
return;
vis[subset] = true;
bool have_children = false;//到子叶终止
for (int left = (subset - 1)⊂ left; left = (left - 1)&subset) //枚举不同二分集合
{
have_children = true;

int right = subset^left;

double d1 = w[right] / w[subset];
double d2 = w[left] / w[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[right][j].R + d2, tree[left][i].R - d1);
if (t.L + t.R < r)
tree[subset].push_back(t);
}
}
if (!have_children)
tree[subset].push_back(Tree());//到子叶终止
}

int main()
{
int T;
scanf("%d", &T);
while (T--)
{
memset(vis, 0, sizeof(vis));
memset(w, 0, sizeof(w));
int s;
scanf("%lf%d", &r, &s);
for (int i = 0; i < s; i++)
{
scanf("%lf", &w[1 << i]);
}
for (int i = 0; i < (1 << s); i++)
{
tree[i].clear();  //捎带初始化//注意初始化位置,既要及时,又要避免将输入清除
for (int j = 0; j < s; j++)
{
if (i&(1 << j) && i!= (1 << j))
w[i] += w[1 << j];
}
}
dfs((1 << s) - 1);

double ans = -1;
for (int i = 0; i < tree[(1 << s) - 1].size(); i++)
ans = max(ans, tree[(1 << s) - 1][i].L + tree[(1 << s) - 1][i].R);
printf("%.10lf\n", ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: