POJ2152 Fire

这是一道dp的题目

dp[i][j]表示如果i地由j地的消防站管的子树最小代价

best[i]表示i点子树的最小代价

dis[i]表示i点到当前点的最小距离

然后best[i]=min(dp[i][j])

dp[i][j]=w[j]+sum(min(best[son],dp[son][j]-w[j]))

转移就行了

还是我太菜了

这种题都不会做

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN=1005;
const int MAXM=2005;
const int inf=0x3f3f3f3f;
inline int read(){
	int x=0,f=1,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;
}
int h[MAXN],nxt[MAXM],to[MAXM],cost[MAXM],cnt;
inline void add(int x,int y,int z){
	nxt[cnt]=h[x];to[cnt]=y;cost[cnt]=z;h[x]=cnt++;
	nxt[cnt]=h[y];to[cnt]=x;cost[cnt]=z;h[y]=cnt++;
}
int w[MAXN],d[MAXN],dp[MAXN][MAXN],dis[MAXN],best[MAXN];
inline void spfa(int x,int fa){
	for(int i=h[x];i!=-1;i=nxt[i])
		if(to[i]!=fa)
			dis[to[i]]=dis[x]+cost[i],spfa(to[i],x);
}
int n;
inline void dfs(int x,int fa){
	for(int i=h[x];i!=-1;i=nxt[i])
		if(to[i]!=fa)
			dfs(to[i],x);
	dis[x]=0;spfa(x,-1);
	best[x]=inf;
	for(int i=1;i<=n;i++){
		if(dis[i]>d[x]) dp[x][i]=inf;
		else{
			dp[x][i]=w[i];
			for(int j=h[x];j!=-1;j=nxt[j])
				if(to[j]!=fa)
					dp[x][i]+=min(best[to[j]],dp[to[j]][i]-w[i]);
		}
		best[x]=min(best[x],dp[x][i]);
	}
}
int main(){
	int T=read();
	while(T--){
		memset(h,-1,sizeof(h));
		cnt=0;
		n=read();
		for(int i=1;i<=n;i++) w[i]=read();
		for(int i=1;i<=n;i++) d[i]=read();
		for(int i=1;i<n;i++){
			int x=read(),y=read(),z=read();
			add(x,y,z);
		}
		dfs(1,-1);
		printf("%d\n",best[1]);
	}
	return 0;
}
posted @ 2019-02-26 09:30  古城独钓  阅读(140)  评论(0编辑  收藏  举报