JLUCPC
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3899
题意:一棵树,给出每个点的权值和每条边的长度,点j到点i的代价为点j的权值乘以连接i和j的边的长度。求点x使得所有点到点x的代价最小,输出最小值。
题解:求出一个点的代价后可以进行相应的转移求出相邻点的代价。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAX 100010 #define inf 0xfffff #define LL long long #pragma comment(linker, "/STACK:1024000000,1024000000") //内存挂 int edge[MAX<<1];//表示第i条边的终点 int next[MAX<<1];//与第i条边同起点的下一条边的位置 int head[MAX<<1];//以i为起点的第一条边的储存位置 int cost[MAX<<1]; LL dp[MAX]; LL value[MAX];//每个结点的权值 LL dist[MAX];//子树的权值和 int cnt=0; void insert(int a,int b,int c)//a起点,b终点 { edge[++cnt]=b; next[cnt]=head[a]; head[a]=cnt; cost[cnt]=c; } void dfs_dist(int x,int pre,int dis) { dp[1]+=(dis*value[x]); dist[x]=value[x]; for(int i=head[x];i!=-1;i=next[i]) { if(edge[i]==pre) continue; dfs_dist(edge[i],x,dis+cost[i]); dist[x]+=dist[edge[i]]; } } void dfs(int x,int pre) { for(int i=head[x];i!=-1;i=next[i]) { if(edge[i]==pre) continue; int k=edge[i]; dp[k]=dp[x]+(dist[1]-dist[k]-dist[k])*cost[i]; //对于一条边,求出这条边上面所以边的长度和和下面所有边的长度和,然后就可以进行转移了 dfs(k,x); } } int main() { int n; int a,b,c; for(;~scanf("%d",&n);) { for(int i=1;i<=n;++i) scanf("%I64d",value+i); cnt=0; memset(dp,0,sizeof(dp)); memset(dist,0,sizeof(dist)); memset(head,-1,sizeof(head)); memset(next,-1,sizeof(next)); for(int i=1;i<n;++i) { scanf("%d%d%d",&a,&b,&c); insert(a,b,c); insert(b,a,c); } dfs_dist(1,-1,0); dfs(1,-1); LL ans=dp[1]; for(int i=2;i<=n;++i) ans=min(ans,dp[i]); printf("%I64d\n",ans); } return 0; }