【树形DP】HDU 4313 Matrix

通道

题意:边权树,有m个点是危险的,现在想将树分成m块使得每块中恰好只有一个危险的点,问最小的花费是多少

思路:

dp[i][0|1以i节点为根节点的子树中,i所在的连通块中没有(有)危险节点的最小花费;

如果i是叶子节点:如果i为危险点dp[i][0] = inf,dp[i][1]= 0;否则dp[i][0] = dp[i][1] = 0;

如果i不是叶子节点:如果i是危险点dp[i][0] = inf , dp[i][1] = sigma min(dp[son][0],dp[son][1]+w);
否则dp[i][0] = sigma min(dp[son][0],dp[son][1]+w),dp[i][1] = min(dp[i][0] – min(dp[son][0],dp[son][1]+w)+dp[son][1])。

代码:

#include <iostream>
#include <cstdio>
#include <memory.h>
#define MIN(a , b) ((a) < (b) ? (a) : (b))
using namespace std;
const __int64 inf = 1LL << 45;
const int maxn = 100002;
struct node
{
    int v;
    __int64 w;
    int next;
}edge[maxn << 1];
int head[maxn];
__int64 dp[maxn][2];
bool machine[maxn];
int n,m,idx;

void init()
{
    memset(head,-1,sizeof(head));
    memset(machine,false,sizeof(machine));
    idx = 0;
    return;
}

void addedge(int u,int v,__int64 w)
{
    edge[idx].v = v;
    edge[idx].w = w;
    edge[idx].next = head[u];
    head[u] = idx++;

    edge[idx].v = u;
    edge[idx].w = w;
    edge[idx].next = head[v];
    head[v] = idx++;
    return;
}


void read()
{
    scanf("%d %d",&n,&m);
    int u,v;
    __int64 w;
    for(int i=1;i<n;i++)
    {
        scanf("%d %d %I64d",&u,&v,&w);
        addedge(u,v,w);
    }
    for(int i=0;i<m;i++)
    {
        scanf("%d",&u);
        machine[u] = true;
    }
    return;
}

void dfs(int st,int pre)
{
    bool leaf = true;
    for(int i=head[st];i != -1;i=edge[i].next)
    {
        if(edge[i].v == pre) continue;
        leaf = false;
        dfs(edge[i].v , st);
    }
    if(leaf)
    {
        dp[st][0] = machine[st] ? inf : 0;
        dp[st][1] = 0;
        return;
    }
    if(machine[st])
    {
        dp[st][0] = inf;
        dp[st][1] = 0;
        for(int i=head[st];i != -1;i=edge[i].next)
        {
            if(edge[i].v == pre) continue;
            dp[st][1] += MIN(dp[edge[i].v][0] , edge[i].w + dp[edge[i].v][1]);
        }
    }
    else
    {
        dp[st][0] = 0;
        dp[st][1] = inf;
        for(int i=head[st];i != -1;i=edge[i].next)
        {
            if(edge[i].v == pre) continue;
            dp[st][0] += MIN(dp[edge[i].v][0] , edge[i].w + dp[edge[i].v][1]);
        }
        for(int i=head[st];i != -1;i=edge[i].next)
        {
            if(edge[i].v == pre) continue;
            dp[st][1] = MIN(dp[st][1] , dp[st][0] - MIN(dp[edge[i].v][0] , edge[i].w + dp[edge[i].v][1]) + dp[edge[i].v][1]);
        }
    }
    return;
}

int main()
{
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {
        init();
        read();;
        dfs(0,-1);
        printf("%I64d\n",MIN(dp[0][0] , dp[0][1]));
    }
    return 0;
}
View Code

 

posted @ 2015-08-05 21:05  mithrilhan  阅读(157)  评论(0编辑  收藏  举报