/*
题目链接:http://poj.org/problem?id=2152
题意:城市树形分布,每个城市修建消防站的有一个花费值cost,且,当该地着火,离他最近的那个消防站必须小于
need,问要保证每个地方都能得到安全防护,需要的最小花费为?
解题思路:令dp[i][j]为,保护i点的消防站修建在j点且以i为根节点,所有孩子即自己都能得到保护的的最小花费
状态转移方程:dp[i][j]=w[j]+sum(min(dp[child][j]-w[j],best[child]));
转载:
非常非常好的一道树状DP!
问题描述:
Z国有n个城市,从1到n给这些城市编号。城市之间连着高速公路,并且每两个城市之间有且只有一条通路。不同的高速公路可能有不同的长度。最近Z国经常发生火灾,所以当地政府决定在某些城市修建一些消防站。在城市k修建一个消防站须要花费大小为的费用。函数W对于不同的城市可能有不同的取值。如果在城市k没有消防站,那么它到离它最近的消防站的距离不能超过。每个城市在不超过距离的前提下,必须选择最近的消防站作为负责站。函数D对于不同的城市可能有不同的取值。为了节省钱,当地政府希望你用最少的总费用修建一些消防站,并且使得这些消防站满足上述的要求。
设:
f[i][j]:表示以i为根的子树里修建一些消防站,并在节点j处修建一消防站,i的负责站必须是j
best[i]:表示以i为根的子树的所有节点都有负责站的最小花费
dist[i]表示i到x的距离,所以没换一个节点,都要再求一次dist[]。
好了下面说下转移方程:
首先选定一个节点(x)为根 ,遍历所有节点
如果d[x]<dist[i],则i点不可能成为x的负责站f[x][i]=INF;
如果d[x]>=dist[i],则i可以成为x的负责站,分三种情况讨论:(y是x的儿子)
A.
当i在以x为根的子树外时,对于x的每个儿子y都有两种选择:选择以y为根的子树内或外的消防站为负责站。当选择以y为根的子树内的消防站为负责站时,其子树所需的最少费用为best[y],当选择以y为根的子树外的消防站为负责站时,y只可以选择i上的消防站作为负责站,此时其子树所需的最少费用为f[k][i]。综上得到
f[x][i]+=min(best[y],f[y][i]);
(其实这块是反过来想的,当i点在x为根的子树外时,如果的x的儿子y选择i作为负责站,那么在i节点与y节点中间的x就一定是选择i了。)
B.
当x==i时,x的每个儿子的选择情况与A中的一样。此时还要加上修建x上的消防站的费用。因此
f[x][i]+=w[x]+min(best[y],f[y][i]);
C.
当x!=i并且i在以x为根的子树内时,此时i必定在x的某个儿子y的子树里。对于x的每个不是y的儿子其选择情况与⑴中的一样,而对于y,它只能选择j作为负责站。综上得到
f[x][i]+=f[y][i]+min(best[k],f[k][i]);(k是x中不是y的所有儿子)
*/
#include<stdio.h>
#include<string.h>
#define MAXN 1005
#define MAXE 2005
#define INF 100000000
#define min(a,b) ((a<b)?a:b)
int head[MAXN],cost[MAXN],need[MAXN],dis[MAXN];
struct Edge{
int node;
int next;
int len;
}edge[MAXE];
int cnt,N;
int dp[MAXN][MAXN],ans[MAXN];
void add(int a,int b,int c)
{
edge[cnt].len=c;edge[cnt].next=head[a];edge[cnt].node=b;head[a]=cnt++;
edge[cnt].len=c;edge[cnt].next=head[b];edge[cnt].node=a;head[b]=cnt++;
}
void dfs(int fa,int root,int sum)
{
int i;
dis[root]=sum;
for(i=head[root];~i;i=edge[i].next)
if(edge[i].node!=fa)
dfs(root,edge[i].node,sum+edge[i].len);
}
void DP(int fa,int root)
{
int i,j;
for(i=head[root];~i;i=edge[i].next)
{
if(edge[i].node!=fa)
DP(root,edge[i].node);
}
dfs(-1,root,0);
ans[root]=INF;
for(i=1;i<=N;i++)
{
if(dis[i]<=need[root])
{
dp[root][i]=cost[i];
for(j=head[root];~j;j=edge[j].next)
{
if(edge[j].node!=fa)
{
dp[root][i]+=min(ans[edge[j].node],dp[edge[j].node][i]-cost[i]);
}
}
if(dp[root][i]<ans[root])ans[root]=dp[root][i];
}
else
dp[root][i]=INF;
}
}
int main()
{
int T,i,a,b,c;
// freopen("in.txt","r",stdin);
for(scanf("%d",&T);T--;)
{
scanf("%d",&N);
for(i=1;i<=N;i++)scanf("%d",&cost[i]);
for(i=1;i<=N;i++)scanf("%d",&need[i]);
memset(head,-1,sizeof(head));
for(i=1,cnt=0;i<N;i++)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
DP(-1,1);
printf("%d\n",ans[1]);
}
return 0;
}
/*
10
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
*/