poj 1155(树形dp)
题意:有一个有线电视网络叶子结点是用户,每个用户有一个愿意支付的金额。然后每条边都有话费。问公司在不亏本的情况下最多能满足多少用户。
思路:dp[v][j] = max(dp[v][j], dp[v][j-k]+dp[x][k]-edge(v, x))
其实就是背包问题,但是一开始TLE了一次,这里要有个优化处理一个节点之前需要初始化一下他最多接着几个用户。这样就AC了。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 #include <queue> 7 #include <set> 8 #include <map> 9 #include <string> 10 #include <math.h> 11 #include <stdlib.h> 12 #include <time.h> 13 #define MP(a, b) make_pair(a, b) 14 #define PB(a) push_back(a) 15 using namespace std; 16 const int LEN = 3010; 17 const int INF = 0x3f3f3f3f; 18 typedef pair<int, int> pii; 19 int n, m, dp[LEN][LEN], vex[LEN], num[LEN]; 20 vector<pii> Map[LEN]; 21 22 void dfs(int v, int fa){ 23 if(v > n-m && v <= n) dp[v][1] = vex[v]; 24 for(int i=0; i<Map[v].size(); i++){ 25 int x = Map[v][i].first; 26 if(x != fa){ 27 dfs(x, v); 28 num[v] += num[x]; 29 for(int j=num[v]; j>=0; j--){ 30 for(int k=0; k<=num[x]; k++){ 31 if(j - k >= 0 && dp[x][k] != -INF && dp[v][j-k] != -INF) 32 dp[v][j] = max(dp[v][j], dp[v][j-k]+dp[x][k]-Map[v][i].second); 33 } 34 } 35 } 36 } 37 } 38 39 void init(){ 40 for(int i=0; i<LEN; i++)Map[i].clear(); 41 memset(num, 0, sizeof num); 42 for(int i=0; i<LEN ;i++){ 43 for(int j=0; j<LEN; j++){ 44 dp[i][j] = -INF; 45 if(j == 0) dp[i][j] = 0; 46 } 47 } 48 } 49 50 int main() 51 { 52 // freopen("in.txt","r",stdin); 53 //freopen("out.txt","w",stdout); 54 55 int a, b, tn; 56 while(scanf("%d%d", &n, &m)!=EOF){ 57 init(); 58 for(int i=1; i<=n-m; i++){ 59 scanf("%d", &tn); 60 for(int j=0; j<tn; j++){ 61 scanf("%d%d", &a, &b); 62 Map[i].PB(MP(a, b)); 63 Map[a].PB(MP(i, b)); 64 } 65 } 66 for(int i=n-m+1; i<=n ;i++){ 67 num[i] = 1; 68 scanf("%d", &vex[i]); 69 } 70 dfs(1, -1); 71 int ans; 72 for(int i=m; i>=0; i--){ 73 if(dp[1][i] >= 0){ 74 ans = i; 75 break; 76 } 77 } 78 printf("%d\n", ans); 79 } 80 return 0; 81 82 }
奔跑吧!少年!趁着你还年轻