题目描述
圣诞节快到了,蒜头君准备做一棵大圣诞树。
这棵树被表示成一组被编号的结点和一些边的集合,树的结点从 1 到 n 编号,树的根永远是 1。每个结点都有一个自身特有的数值,称为它的权重,各个结点的权重可能不同。对于一棵做完的树来说,每条边都有一个价值 ve,若设这条边 e 连接结点 i 和结点 j,且 i 为 j的父结点(根是最老的祖先),则该边的价值ve=sj*we,sj表示结点 j 的所有子孙及它自己的权重之和,we表示边 e 的权值。
现在蒜头君想造一棵树,他有 m 条边可以选择,使得树上所有边的总价值最小,并且所有的点都在树上,因为蒜头君喜欢大树。
输入格式
第一行输入两个整数 n 和 m(0≤n,m≤50,000),表示结点总数和可供选择的边数。
接下来输入一行,输入 n 个整数,依次表示每个结点的权重。
接下来输入 m 行,每行输入 3 个正整数a,b,c(1≤a,b,≤n,1≤c≤10,000),表示结点 a 和结点 b 之间有一条权值为 c 的边可供造树选择。
输出格式
输出一行,如果构造不出这样的树,请输出No Answer,否则输出一个整数,表示造树的最小价值。
样例输入
4 4
10 20 30 40
1 2 3
2 3 2
1 3 5
2 4 1
样例输出
370
简要分析
这道题原本是求每条边的价值之和,但是根据公式 Ve=Sj × We 分析一下,就可以推导出
最后的总价值之和 =(顶点① 的权值× 顶点①到根①的边总权值和) + (顶点②的权值 × 顶点②到根①的边总权值和) + … + (顶点n的权值 × 顶点n到根①的边总权值和)
各个顶点的权值都是定了的,因此本题也就转化成求顶点1到各个顶点的最短路径。
ac代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
using namespace std;
const int MAX=50001;
int n,m;
struct edge{
int v,w,next;
edge(){}
edge(int _v,int _w,int _n):v(_v),w(_w),next(_n){}
}e[MAX*2];
int w[MAX],p[MAX],dist[MAX];//存储点的权值,各点指向边的头指针,1到各点的距离
bool vst[MAX];//判断各点是否拜访
typedef pair<int,int> PII;
set<PII,less<PII> > min_heap;//存储点和点到1的距离的数据集的集合,并按照距离从小到大排序
bool dijkstra(int s){
memset(vst,0,sizeof(vst));
memset(dist,0x3f,sizeof(dist));
dist[s]=0;//第一个点初始化为未拜访
min_heap.insert(make_pair(0,s));//将起点放入集合
for(int i=0;i<n;i++){
if(min_heap.size()==0)
return false;
set<PII,less<PII> >::iterator iter=min_heap.begin();//取出集合中距离最小的点
int u=iter->second;//存储距离最小的点的编号
vst[u]=true;//标记为已访问
min_heap.erase(*iter);//擦除这个点
for(int j=p[u];j+1;j=e[j].next){//邻接表用法
int v=e[j].v;
if(!vst[v]&&dist[v]>dist[u]+e[j].w){//这个点未求出过最小距离,并且距离可更新
min_heap.erase(make_pair(dist[v],v));//擦除原有数据
dist[v]=dist[u]+e[j].w;//更新数据
min_heap.insert(make_pair(dist[v],v));//放入新数据
}
}
}
return true;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&w[i]);
memset(p,-1,sizeof(p));
for(int i=0;i<2*m;){
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
e[i]=edge(v,c,p[u]);
p[u]=i++;
e[i]=edge(u,c,p[v]);
p[v]=i++;
}
if(dijkstra(1)){
long long sum=0;
for(int i=1;i<=n;i++){
sum+=dist[i]*w[i];
}
cout<<sum<<endl;
}
else
cout<<"No Answer"<<endl;
return 0;//give me five
}