题目的大意是计算一颗树的最小的价值,而每个节点指向他的父亲节点的边的价值为此节点的价值加上他的所有儿子节点的价值(包括儿子节点的子节点)乘以这条边的价值。而这个问题可以转换为求每个节点到根节点的最短路,然后用此最短路的值乘以此节点的价值就是这个节点贡献的价值,所有的节点除根节点的贡献的价值的和就是此题的答案。如果存在最短路为INF,则证明不存在此树。
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#define maxc 100005
#define maxn 50005
#define maxq 200000
#define mem(a, b) memset(a, b, sizeof(a))
using namespace std;
long long head[maxc], dp[maxn], que[maxq], values[maxn], sizes, n, inf;
bool vis[maxn];
struct node
{
long long to;
long long w;
long long next;
}nd[maxc];
void inits()
{
sizes = 0;
mem(head, -1);
inf = 1;
for(int i = 0;i < 18;i++)
inf *= 10;
}
void add(long long v, long long u, long long w)
{
nd[sizes].to = u;
nd[sizes].w = w;
nd[sizes].next = head[v];
head[v] = sizes++;
}
void spfa(long long a)
{
long long i, k, heads = 0, fails = 0;
mem(vis, 0);
for(i = 0;i <= n;i++)
dp[i] = inf;
que[heads++] = a;
vis[a] = 1;
dp[a] = 0;
while(fails != heads)
{
k = que[fails++];
fails %= maxq;
vis[k] = 0;
for(i = head[k];i != -1;i = nd[i].next)
{
long long v = nd[i].to;
long long w = nd[i].w;
if(dp[v] > dp[k] + w)
{
dp[v] = dp[k] + w;
if(!vis[v])
{
que[heads++] = v;
heads %= maxq;
}
}
}
}
return;
}
int main(int argc, char *argv[])
{
int cas;
long long e, i, a, b, c, ans;
scanf("%d", &cas);
while(cas--)
{
inits();
scanf("%lld%lld", &n, &e);
for(i = 1;i <= n;i++)
scanf("%lld", &values[i]);
for(i = 0;i < e;i++)
{
scanf("%lld%lld%lld", &a, &b, &c);
add(a, b, c);
add(b, a, c);
}
spfa(1);
ans = 0;
int flag = 0;
for(i = 2;i <= n;i++)
{
if(dp[i] < inf)
ans += (dp[i] * values[i]);
else
{
flag = 1;
break;
}
}
if(!flag)
printf("%lld\n", ans);
else
printf("No Answer\n");
}
return 0;
}