POJ 2152 Fire(树形dp)
http://poj.org/problem?id=2152
题意:
n个节点组成的树,要在树一些点上建立消防站,每个点建站都有个cost[i],每个点如果不在当前的点上建站,也要依赖其他的消防站,并且距离不超过limit[i]。求符合上述条件的最小费用建站费用。
思路:
感觉有点无从下手,如果不会的话可以先看一下一张一弛,解题之道这篇论文。
其实说白了,就是暴力枚举。
先设立一个辅助数组$best$,$best[u]$表示以u及其子树的最小费用,$dp[u][j]$表示u依赖j节点时(也就是j节点建消防站)及其子节点的最小费用。(如果u和j之间的距离>$limit[u]$则不需要考虑)
那么状态转移方程就是:$dp[u][j]+=min(dp[v][j]-cost[j],best[v])$,$dp[v][j]-cost[j]$表示v也依赖j节点时的最小费用,因为前面已经计算过了$cost[j]$,所以这里需要减去。
在每次考虑了u可以依赖的节点j后,更新一下最小值$best[u]$即可。最后的答案即是$best[1]$。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<stack> 7 #include<queue> 8 #include<cmath> 9 #include<map> 10 #include<set> 11 using namespace std; 12 typedef long long ll; 13 typedef pair<int,int> pll; 14 const int INF = 0x3f3f3f3f; 15 const int maxn=1000+5; 16 17 int n,root; 18 int cost[maxn],limit[maxn],best[maxn],dp[maxn][maxn],dis[maxn][maxn]; 19 vector<pll> G[maxn]; 20 21 void calc_dis(int u, int fa, int d) 22 { 23 dis[root][u]=d; 24 for(int i=0;i<G[u].size();i++) 25 { 26 int v=G[u][i].first; 27 int w=G[u][i].second; 28 if(v==fa) continue; 29 calc_dis(v,u,d+w); 30 } 31 } 32 33 void dfs(int u, int fa) 34 { 35 for(int i=0;i<G[u].size();i++) 36 { 37 int v=G[u][i].first; 38 if(v==fa) continue; 39 dfs(v,u); 40 } 41 for(int j=1;j<=n;j++) 42 { 43 if(dis[u][j]>limit[u]) continue; 44 dp[u][j]=cost[j]; 45 for(int i=0;i<G[u].size();i++) 46 { 47 int v=G[u][i].first; 48 int w=G[u][i].second; 49 if(v==fa) continue; 50 dp[u][j]+=min(dp[v][j]-cost[j],best[v]); 51 } 52 best[u]=min(best[u],dp[u][j]); 53 } 54 } 55 56 int main() 57 { 58 //freopen("in.txt","r",stdin); 59 int T; 60 int kase=0; 61 scanf("%d",&T); 62 while(T--) 63 { 64 scanf("%d",&n); 65 for(int i=1;i<=n;i++) {G[i].clear();scanf("%d",&cost[i]);} 66 for(int i=1;i<=n;i++) scanf("%d",&limit[i]); 67 for(int i=1;i<n;i++) 68 { 69 int u,v,w; 70 scanf("%d%d%d",&u,&v,&w); 71 G[u].push_back(make_pair(v,w)); 72 G[v].push_back(make_pair(u,w)); 73 } 74 for(int i=1;i<=n;i++) {root=i;calc_dis(i,-1,0);} 75 memset(dp,0x3f,sizeof(dp)); 76 memset(best,0x3f,sizeof(best)); 77 dfs(1,-1); 78 printf("%d\n",best[1]); 79 } 80 return 0; 81 }