HDU 4274 - Spy's Work(树形DP)

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=4274

题意:

给出n个点的树,树上的节点权值为其子树的节点权值和(大于等于1),给出一些节点的限制条件,判断这些条件是否成立。

思路:

midp:表示该节点权值的下限,madp:表示该节点权值的上限。

按照题目所给的限制条件,赋值dp数组。

在dfs中更新 midp,节点的权值上限无法确定,判断midp<=madp 是否成立。

AC.

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;
typedef long long ll;
const ll inf = 1e17+5;
const int maxn = 10005;
int n;

int tol, head[maxn];
struct Edge{
    int to, next;
}edge[maxn];
void addedge(int u, int v)
{
    edge[tol].to = v;
    edge[tol].next = head[u];
    head[u] = tol++;
}

ll midp[maxn], madp[maxn];
ll son[maxn];
bool dfs(int u)
{
    ll mins = 1;
    son[u] = 1;
    for(int i = head[u]; ~i; i = edge[i].next) {
        int  v = edge[i].to;

        bool flag = dfs(v);
        if(flag) {
             son[u] += son[v];
             mins += midp[v];
        }
        else return false;
    }

    midp[u] = max(mins, midp[u]);
    return midp[u] <= madp[u];
}

void init()
{
    tol = 0;
    memset(head, -1, sizeof(head));
    for(int i = 1; i <= n; ++i) {
        midp[i] = 1;
        madp[i] = inf;
    }
}
int main()
{
   // freopen("in", "r", stdin);
    while(~scanf("%d", &n)) {
        int u;
        init();
        for(int v = 2; v <= n; ++v) {
            scanf("%d", &u);
            addedge(u, v);
        }

        int m;
        scanf("%d", &m);
        for(int i = 0; i < m; ++i) {
            int vl;
            char ch;
            scanf("%d %c %d", &u, &ch, &vl);
            if(ch == '=') {
                midp[u] = max(midp[u], (ll)vl);
                madp[u] = min(madp[u], (ll)vl);
            }
            if(ch == '>') {
                midp[u] = max(midp[u], (ll)vl+1);
            }
            if(ch == '<') {
                madp[u] = min(madp[u], (ll)vl-1);
            }
        }

//        for(int i = 1; i <= n; ++i) {
//            printf("i =%d: (%lld, %lld)\n", i, midp[i], madp[i]);
//        }

        if(dfs(1)) {
            printf("True\n");
        }
        else printf("Lie\n");
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值