1. 程式人生 > >樹形dp——覆蓋所有邊的最少費用(Protecting Zonk)

樹形dp——覆蓋所有邊的最少費用(Protecting Zonk)

scan sizeof include memset nbsp cti 需要 節點 ret

一、問題描述

有一個n(n<=10000)個節點的無根樹。有兩種裝置A,B,每種都有無限多個。
1.在某個節點X使用A裝置需要C1(C1<=1000)的花費,並且此時與節點X相連的邊都被覆蓋
2.在某個節點X使用B裝置需要C2(C2<=1000)的花費,並且此時與節點X相連的邊以及與節點X相連的點相連的邊都被覆蓋
求覆蓋所有邊的最小花費

二、問題分析

dp[u][0]:u沒有安裝裝置,且u的子節點下的邊都被覆蓋
dp[u][1]:u安裝裝置A
dp[u][2]:u安裝裝置B
dp[u][3]:u沒有安裝裝置,且v可以不安裝裝置

dp[u][0]=Sum( min(dp[v][1],dp[v][2]) );
dp[u][1]=min( C1+Sum( min(dp[v][0],dp[v][1],dp[v][2]) ),Sum( min(dp[v][2],dp[v][1],dp[v][0]) 且至少有一個子節點選擇B) )
dp[u][2]=C2+Sum( min(dp[v][0],dp[v][1],dp[v][2],dp[v][3]) )
dp[u][3]=Sum(min(dp[v][0],dp[v][1],dp[v][2]))

三、代碼實現

 1 #include<stdio.h>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 const int INF = 0x3f3f3f3f;
 9 const int maxn = 100000 + 10;
10 struct Edge
11 {
12     int to, next;
13 }e[maxn * 2];
14 
15 //dp[u][0]:u沒有安裝裝置, 且u的子節點下的邊都被覆蓋
16 //dp[u][1] : u安裝裝置A 17 //dp[u][2] : u安裝裝置B 18 //dp[u][3] : u沒有安裝裝置, 且v可以不安裝裝置 19 int head[maxn], d[maxn][4]; 20 int tot,n,C1,C2; 21 22 int mostmin(int a, int b, int c) 23 { 24 return min(a, min(b, c)); 25 } 26 27 void init() 28 { 29 tot = 0; 30 memset(head, -1
, sizeof(head)); 31 } 32 33 void addadge(int from, int to) 34 { 35 e[tot].to = to; 36 e[tot].next = head[from]; 37 head[from] = tot++; 38 } 39 40 void dfs(int u, int fa) 41 { 42 d[u][0] = 0; d[u][1] = C1; d[u][2] = C2; d[u][3] = 0; 43 int flag = 0, sum = 0, mi = INF; 44 for (int i = head[u]; i != -1; i = e[i].next) 45 { 46 int v = e[i].to; 47 if (v == fa) continue; 48 dfs(v, u); 49 d[u][0] += min(d[v][1], d[v][2]); 50 d[u][1] += mostmin(d[v][0], d[v][1], d[v][2]); 51 d[u][2] += min(mostmin(d[v][0], d[v][1], d[v][2]), d[v][3]); 52 d[u][3] += mostmin(d[v][0], d[v][1], d[v][2]); 53 int tmp = mostmin(d[v][0], d[v][1], d[v][2]); 54 sum += tmp; 55 mi = min(mi, d[v][2] - tmp); 56 } 57 sum += mi; 58 d[u][1] = min(d[u][1], sum); 59 } 60 61 int main() 62 { 63 while (scanf("%d%d%d",&n,&C1,&C2) == 3 && n) 64 { 65 init(); 66 int u, v; 67 68 for (int i = 0; i < n - 1; i++) 69 { 70 scanf("%d%d", &u, &v); 71 addadge(u, v); 72 addadge(v, u); 73 } 74 dfs(1, 0); 75 printf("%d\n", mostmin(d[1][0], d[1][1], d[1][2])); 76 } 77 return 0; 78 }

樹形dp——覆蓋所有邊的最少費用(Protecting Zonk)