题目链接:
http://poj.org/problem?id=3013
题意:
给你一颗树,每棵子树的造价 = 子树上所有节点的和 * 子树和父亲节点的权值。求最小造价,如果不能造出来输出No Answer。
题解:
其实这颗树的造价就是源点1到每个点的距离与每个点的造价的乘积。故可以转化成最短路求解,求单源最短路可以使用SPFA求。
AC代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#define MAXN 60000
using namespace std;
long long dist[MAXN],head[MAXN];
bool vis[MAXN];
int cnt,n,m;
int weight[MAXN];
const unsigned long long INF = 9999999999LL;
queue <int> Q;
struct node
{
int u,v,w,next;
}edge[MAXN * 2];
void add(int u, int v, int w)
{
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].u=v;
edge[cnt].v=u;
edge[cnt].w=w;
edge[cnt].next=head[v];
head[v]=cnt++;
}
void spfa(int s)
{
for(int i=0; i<=n; i++)
{
dist[i]=INF;
vis[i]=false;
}
dist[s]=0;
Q.push(s);
vis[s]=true;
while(!Q.empty())
{
int u=Q.front();
Q.pop();
vis[u]=false;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(dist[u]+edge[i].w<dist[v])
{
dist[v]=dist[u]+edge[i].w;
if(!vis[v])
{
vis[v]=true;
Q.push(v);
}
}
}
}
}
void init()
{
while(!Q.empty())
{
Q.pop();
}
cnt=0;
memset(head, -1, sizeof(head));
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
init();
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d", &weight[i]);
while(m--)
{
int a,b,c;
scanf("%d %d %d", &a, &b, &c);
add(a,b,c);
}
spfa(1);
int flag = 0;
long long ans = 0;
for(int i = 1; i <= n; i++)
{
if(dist[i] == INF)
{
flag = 1;
break;
}
ans += dist[i] * weight[i];
}
if(!flag)
printf("%I64d\n", ans);
else
printf("No Answer\n");
}
return 0;
}