洛谷P1273 有線電視網【樹形dp】

題目https://www.luogu.org/problemnew/show/P1273ios

題意:一棵樹,葉子節點是用戶,天天邊有一個權值表示花費,每個用戶有一個值表示他們會交的錢。spa

問在不虧本的狀況下,最多能夠選擇多少個用戶,讓他們獲得從根節點(1)發送出的服務。code

思路:原本很天真的覺得是先dfs處理出每一個葉子節點到根的淨利潤,而後揹包。【太傻逼了】blog

可是同一棵子樹上的節點共用了一段路徑,這裏是不用重複算的。get

因此要樹形dp,$dp[i][j]$表示以$i$爲根的子樹上選了$j$個節點。string

$dp[i][j] = max(dp[i][j], dp[i][j-k]+dp[son][k]-e.w)$it

$j$的範圍是$i$的子孫數,這個須要dfs的時候統計,$k$的範圍是$son$這棵子樹的大小。io

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<map>
 4 #include<set>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<cmath> 
 9 #include<stack>
10 #include<queue>
11 #include<iostream>
12 
13 #define inf 0x3f3f3f3f
14 using namespace std;
15 typedef long long LL;
16 typedef pair<int, int> pr;
17 
18 int n, m;
19 const int maxn = 3005;
20 int head[maxn], tot;
21 struct edge{
22     int to, w, nxt;
23 }e[maxn];
24 int pay[maxn];
25 int dp[maxn][maxn];
26 
27 void add(int x, int y, int c)
28 {
29     e[++tot].to = y;
30     e[tot].w = c;
31     e[tot].nxt = head[x];
32     head[x] = tot;
33 }
34 
35 int dfs(int now)
36 {
37     if(now > n - m){
38         dp[now][1] = pay[now];
39         return 1;
40     }
41     int sum = 0, son = 0;
42     for(int i = head[now]; i; i = e[i].nxt){
43         int to = e[i].to;
44         //printf("%d %d\n", now, e[i].to);
45         son = dfs(to);
46         sum += son;
47         for(int j = sum; j > 0; j--){
48             for(int k = 1; k <= son; k++){
49                 if(j >= k)dp[now][j] = max(dp[now][j], dp[now][j - k] + dp[to][k] - e[i].w);
50             }
51         }
52     }
53     return sum;
54 }
55 
56 int main()
57 {
58     memset(dp, ~0x3f, sizeof(dp));
59     memset(head, 0, sizeof(head));
60     scanf("%d%d", &n, &m);
61     for(int i = 1; i <= n - m; i++){
62         int k;
63         scanf("%d", &k);
64         while(k--){
65             int a, c;
66             scanf("%d%d", &a, &c);
67             add(i, a, c);
68         }
69         dp[i][0] = 0;
70     }
71     for(int i = n - m + 1; i <= n; i++){
72         scanf("%d", &pay[i]);
73         dp[i][0] = 0;
74     }
75     dfs(1);
76     for(int i = m; i > 0; i--){
77         if(dp[1][i] >= 0){
78             printf("%d\n", i);
79             break;
80         }
81     }
82 }
相關文章
相關標籤/搜索