【树形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; }