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 }

 

posted @ 2017-08-28 10:59  Kayden_Cheung  阅读(217)  评论(0编辑  收藏  举报
//目录