Description
Country Z has N cities, which are numbered from 1 to N. Cities are connected by highways, and there is exact one path between two different cities. Recently country Z often caught fire, so the government decided to build some firehouses in some cities. Build a firehouse in city K cost W(K). W for different cities may be different. If there is not firehouse in city K, the distance between it and the nearest city which has a firehouse, can’t be more than D(K). D for different cities also may be different. To save money, the government wants you to calculate the minimum cost to build firehouses.
Input
The first line of input contains a single integer T representing the number of test cases. The following T blocks each represents a test case.
The first line of each block contains an integer N (1 < N <= 1000). The second line contains N numbers separated by one or more blanks. The I-th number means W(I) (0 < W(I) <= 10000). The third line contains N numbers separated by one or more blanks. The I-th number means D(I) (0 <= D(I) <= 10000). The following N-1 lines each contains three integers u, v, L (1 <= u, v <= N,0 < L <= 1000), which means there is a highway between city u and v of length L.
Output
For each test case output the minimum cost on a single line.
Sample Input
5
5
1 1 1 1 1
1 1 1 1 1
1 2 1
2 3 1
3 4 1
4 5 1
5
1 1 1 1 1
2 1 1 1 2
1 2 1
2 3 1
3 4 1
4 5 1
5
1 1 3 1 1
2 1 1 1 2
1 2 1
2 3 1
3 4 1
4 5 1
4
2 1 1 1
3 4 3 2
1 2 3
1 3 3
1 4 2
4
4 1 1 1
3 4 3 2
1 2 3
1 3 3
1 4 2
Sample Output
2
1
2
2
3
Source
POJ Monthly,Lou Tiancheng
题意:给你一颗树,边上权值表示距离,一个点上可以建消防站,花费为 costi ,一个节点要么建消防站,要么周围 di 距离内必须有一个消防站,求覆盖全图的最小花费。
神一般的解法
设 ans[u] 为u的子树的答案, dp[u][v] 表示u节点被v保护的答案, dist[u][v] 表示u到v的距离。
因为 d[i] 不为负,所以可以看看v保护u时是否可以保护u的儿子,以此来更新。
具体来说就是若v可以保护u,则 dp[u][v]=cost[v]+∑min(dp[k][v]−cost[v],ans[k]) ,其中k是u的儿子。具体来说就是先选上v,然后若v能保护k,则取min,减去cost[v]是因为在计算k的时候算了一遍,所以要剪掉防止重复。
若v不可以保护u,则dp[u][v]=INF。
算完之后, ans[u]=min{dp[u][i]}
要先递归,回溯的时候计算…
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int INF = 1000000010;
const int SZ = 2010;
int cost[SZ],d[SZ],n;
int dist[SZ][SZ];
int head[SZ],nxt[SZ],tot = 1;
struct edge{
int t,d;
}l[SZ];
void build(int f,int t,int d)
{
l[++ tot].t = t;
l[tot].d = d;
nxt[tot] = head[f];
head[f] = tot;
}
queue<int> q;
void getdist(int dist[],int s)
{
dist[s] = 0;
q.push(s);
while(q.size())
{
int u = q.front(); q.pop();
for(int i = head[u];i;i = nxt[i])
{
int v = l[i].t;
if(!dist[v] && v != s)
dist[v] = dist[u] + l[i].d,q.push(v);
}
}
}
int dp[SZ][SZ],ans[SZ];
void dfs(int u,int fa)
{
for(int i = head[u];i;i = nxt[i])
{
int v = l[i].t;
if(v == fa) continue;
dfs(v,u);
}
for(int v = 1;v <= n;v ++)
{
if(dist[u][v] <= d[u])
{
int tmp = 0;
for(int i = head[u];i;i = nxt[i])
{
int k = l[i].t;
if(k == fa) continue;
tmp += min(dp[k][v] - cost[v],ans[k]);
}
dp[u][v] = cost[v] + tmp;
}
else
dp[u][v] = INF;
}
for(int i = 1;i <= n;i ++)
ans[u] = min(ans[u],dp[u][i]);
}
void init()
{
tot = 1;
memset(head,0,sizeof(head));
memset(dp,0,sizeof(dp));
memset(dist,0,sizeof(dist));
memset(ans,63,sizeof(ans));
}
int main()
{
int T;
scanf("%d",&T);
while(T --)
{
init();
scanf("%d",&n);
for(int i = 1;i <= n;i ++)
scanf("%d",&cost[i]);
for(int i = 1;i <= n;i ++)
scanf("%d",&d[i]);
for(int i = 1;i <= n - 1;i ++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
build(a,b,c); build(b,a,c);
}
for(int i = 1;i <= n;i ++)
getdist(dist[i],i);
dfs(1,0);
printf("%d\n",ans[1]);
}
return 0;
}