题目大意:有一棵树,每个点有个权值,每条边有个权值,求这棵树的整体权值,如果不能组成一棵树,就输出No Answer
思路:借鉴百度到的分析,最小总花费=每条边(u,v)*v的子树中各结点的重量
此题就转化为了求根节点到每个点的最短路
注意此题INF要设置大一点,我一开始用的0x7fffffff,WA了,改成了20000000000就AC了,因为点的数目太多,求最短路用spfa算法,或者堆优化的dijkstra
AC代码
<span style="font-family:KaiTi_GB2312;font-size:18px;">#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN=50005;
const long long INF = 20000000000;
struct edges
{
int to,weight,next;
} edge[MAXN*2];
long long d[MAXN];
int weight[MAXN];
bool vis[MAXN]; //是否在队列中
int edgehead[MAXN]; //由同一个from连接的to的下一个to
int k,m,n,t;
long long ans;
void addedge(int from,int to, int val)
{
edge[k].next = edgehead[from];
edge[k].to = to;
edge[k].weight = val;
edgehead[from] = k++;
}
void spfa(int f)
{
queue<int> q;
for(int i = 0; i <= n; i++)
{
vis[i] = false;
d[i] = INF;
}
q.push(f);
vis[f] = true;
d[f] = 0;
while(!q.empty())
{
int tem = q.front();
q.pop();
vis[tem] = false;
for(int i = edgehead[tem]; i; i = edge[i].next)
{
if(d[edge[i].to]>d[tem]+edge[i].weight)
{
//path[to]=x; 求路径用
d[edge[i].to] = d[tem]+edge[i].weight;
if(!vis[edge[i].to])
{
q.push(edge[i].to);
vis[edge[i].to] = true;
}
}
}
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
ans = 0;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
scanf("%d",&weight[i]);
memset(edgehead,0,sizeof(edgehead)); //初始化,不然死循环
int u,v,w;
k = 1;
for(int i = 0; i < m; i++)
{
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w); //无向图加入两次
addedge(v,u,w);
}
spfa(1);
int flag = 1;
for(int i = 2; i <= n; i++)
{
if(d[i] == INF)
{
flag = 0;
break;
}
ans += weight[i] * d[i];
}
if(flag)
printf("%I64d\n",ans);
else printf("No Answer\n");
}
}
</span>