您的位置:首页 > 其它

UVALive 6631|Jingle Balls|树形DP

2017-12-03 00:17 375 查看

题目大意

一棵树的叶节点一开始至多有一个球,要求移动最少数量的球使得对于每个节点其两子树的球的数量差至多为1。

题目原文

It will soon be time to decorate the Christmas tree. The NWERC judges are already debating the

optimal way to put decorations in a tree. They agree that it is essential to distribute the decorations

evenly over the branches of the tree.

This problem is limited to binary Christmas trees. Such trees consist of a trunk, which splits into

two subtrees. Each subtree may itself split further into two smaller subtrees and so on. A subtree that

does not split any further is a twig. A twig may be decorated by attaching at most one ball to it.

Figure 1 — Example of a tree with subtrees, twigs and one ball.

A decorated tree has an even distribution of balls if and only if the following requirement is satisfied:

At every point where a (sub)tree splits into two smaller subtrees t1 and t2, the total number of balls

in the left subtree N(t1) and the total number of balls in the right subtree N(t2) must either be equal

or differ by one. That is: |N(t1) − N(t2)| ≤ 1.

In their enthusiasm, the judges initially attach balls to arbitrary twigs in the tree. When they can

not find any more balls to put in the tree, they stand back and consider the result. In most cases,

the distribution of the balls is not quite even. They decide to fix this by moving some of the balls to

different twigs.

Given the structure of the tree and the initial locations of the balls, calculate the minimum number

of balls that must be moved to achieve an even distribution as defined above.

Note that it is not allowed to add new balls to the tree or to permanently remove balls from the

tree. The only way in which the tree may be changed is by moving balls to different twigs.

输入

For each test case, the input consists of one line describing a decorated tree.

The description of a tree consists of a recursive description of its subtrees. A (sub)tree is represented

by a string in one of the following forms:

• The string ‘()’ represents a twig without a ball.

• The string ‘(B)’ represents a twig with a ball attached to it.

• The string ‘(t1t2)’ represents a (sub)tree that splits into the two smaller subtrees represented by

t1 and t2, where t1 and t2 are strings in one of the forms listed here.

A tree contains at least 2 and at most 1000 twigs.

输出

For each test case, print one line of output.

If it is possible to distribute the balls evenly through the tree, print the minimum number of balls

that must be moved to satisfy the requirement of even distribution.

If it is not possible to distribute the balls evenly, print the word ‘impossible’.

样例输入

((B)())
((((B)(B))((B)()))(B))
(()(((B)(B))(B)))


样例输出

0
impossible
1


题解

显然是树形DP。

f[i][j]
表示第i个节点有j个球的最少移动球的个数。

那么显然如果i为叶节点时,如果i原来就有球,那么
f[i][1]=0
f[i][0]=1
比较显然。如果i原来没有球,那么
f[i][0]=f[i][1]=0
。我们只需要算一次移动就可以了,如果
f[i][1]=1
那么答案会翻倍。最终结果除2也可以。

那么对于非叶节点,如果j为奇数,那么
f[i][j]=\min\{f[left[i]][j/2]+f[right[i]][j/2+1],f[left[i]][j/2+1]+f[right[i]][j/2]\}
,因为差至多为1,那么只有2种情况。如果j为偶数,那么显然
f[i][j]=f[left[i]][j/2]+f[right[i]][j/2]


代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int inf = 1e9;
const int N = 5005;
// ball[] == -1 -> not a leaf.
int ball
, L
, R
, dp

;
char str[32768];
int id, sum;

void parse(char *str, int &t, int l, int r) {
t = ++ id;
if (l + 1 == r || l + 2 == r) {
ball[t] = l + 2 == r;
sum += ball[t];
return;
}
int x = 0, mid;
for (mid = l + 1; mid < r; ++ mid) {
if (str[mid] == '(') ++ x;
if (str[mid] == ')') -- x;
if (x == 0) break;
}
parse(str, L[t], l + 1, mid);
parse(str, R[t], mid + 1, r - 1);
}

int solve(int t, int sum) {
if (dp[t][sum] != -1)
return dp[t][sum];

// if leaf
if (ball[t] != -1) {
if (sum > 1) dp[t][sum] = inf;
else if (ball[t]) { // has initial ball
dp[t][0] = 1;
dp[t][1] = 0;
} else {
dp[t][0] = 0;
dp[t][1] = 1;
}
return dp[t][sum];
}
if (sum & 1)
dp[t][sum] = min(
solve(L[t], sum / 2) + solve(R[t], sum / 2 + 1),
solve(L[t], sum / 2 + 1) + solve(R[t], sum / 2)
);
else
dp[t][sum] = solve(L[t], sum / 2) + solve(R[t], sum / 2);
if (dp[t][sum] > inf) dp[t][sum] = inf;
return dp[t][sum];
}

int main() {
while (scanf("%s", str + 1) != EOF) {
int len = strlen(str + 1), root;
id = sum = 0;
memset(ball, -1, sizeof ball);
memset(dp, -1, sizeof dp);
parse(str, root, 1, len);
solve(root, sum);

if (dp[1][sum] == inf)
puts("impossible");
else
printf("%d\n", dp[1][sum]);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: