POJ2152
树形dp,每次先dfs一遍求出距离再枚举所有点转移即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } #define MAXN 1010 int N,T,d[MAXN],c[MAXN]; struct EdgeNode{int next,to,dis;}edge[MAXN<<1]; int head[MAXN],cnt=1; int f[MAXN][MAXN],g[MAXN],deep[MAXN]; inline void AddEdge(int u,int v,int w) {cnt++; edge[cnt].next=head[u]; edge[cnt].to=v; edge[cnt].dis=w; head[u]=cnt;} inline void InsertEdge(int u,int v,int w) {AddEdge(u,v,w); AddEdge(v,u,w);} inline void DFS_1(int now,int last) { for (int i=head[now]; i; i=edge[i].next) if (edge[i].to!=last) deep[edge[i].to]=deep[now]+edge[i].dis, DFS_1(edge[i].to,now); } inline void DFS_2(int now,int last) { for (int i=head[now]; i; i=edge[i].next) if (edge[i].to!=last) DFS_2(edge[i].to,now); deep[now]=0; DFS_1(now,0); for (int j=1; j<=N; j++) if (deep[j]<=d[now]) { f[now][j]=c[j]; for (int i=head[now]; i; i=edge[i].next) if (edge[i].to!=last) f[now][j]+=min(g[edge[i].to],f[edge[i].to][j]-c[j]); g[now]=min(g[now],f[now][j]); } } int main() { T=read(); while (T--) { N=read(); for (int i=1; i<=N; i++) c[i]=read(); for (int i=1; i<=N; i++) d[i]=read(); cnt=1; memset(head,0,sizeof(head)); for (int i=1,x,y,z; i<=N-1; i++) x=read(),y=read(),z=read(),InsertEdge(x,y,z); memset(f,63,sizeof(f)); memset(g,63,sizeof(g)); DFS_2(1,0); // for (int i=1; i<=N; i++) // for (int j=1; j<=N; j++) // printf("%d %d %d\n",i,j,f[i][j]); printf("%d\n",g[1]); } return 0; }