UVALive 6631|Jingle Balls|树形DP

题目大意

一棵树的叶节点一开始至多有一个球,要求移动最少数量的球使得对于每个节点其两子树的球的数量差至多为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]=0f[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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值