题目大意
一棵树的叶节点一开始至多有一个球,要求移动最少数量的球使得对于每个节点其两子树的球的数量差至多为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[N], L[N], R[N], dp[N][N];
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;
}