计蒜客 圣诞树

问题描述

圣诞节快到了,蒜头君准备做一棵大圣诞树。 这棵树被表示成一组被编号的结点和一些边的集合,树的结点从 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

解题思路:其公式相加的含义可以理解为求单源点到各个顶点的路径乘上该点的权值和 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX_N=50010;
const int MAX_M=100010;
int inf=0x3f3f3f3f;
int p[MAX_N],eid;
int vst[MAX_N];
int dst[MAX_N];
int val[MAX_N];
struct edge{
	int v,w,next;
}e[MAX_M];
void init(){
	memset(p,-1,sizeof(p));
	eid=0;
}  
void insert(int u,int v,int w){
	e[eid].v=v;
	e[eid].w=w;
	e[eid].next=p[u];
	p[u]=eid++;
}
int n,m;
typedef pair<int,int> PII;
set<PII,less<PII> >min_heap;
bool dijkstra(int s){
	memset(vst,0,sizeof(vst));
	memset(dst,inf,sizeof(dst));
	min_heap.insert(make_pair(0,s));
	dst[s]=0;
	for(int i=1;i<=n;i++){
		if(min_heap.size()==0)
		   return  false;
		auto it=min_heap.begin();
		min_heap.erase(*it);
		int v=it->second;
		vst[v]=1;
		for(int j=p[v];j+1;j=e[j].next)
	    {
	    	int x=e[j].v;
	    	if(!vst[x]&&dst[v]+e[j].w<dst[x]){
	    		min_heap.erase(make_pair(dst[x],x));
	    		dst[x]=dst[v]+e[j].w;
	    		min_heap.insert(make_pair(dst[x],x));
			}
	    	
		}
		
	} 
	return true;   
	}
int main(){
	init();
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&val[i]);
	}
	int u,v,w;
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&u,&v,&w);
		insert(u,v,w);
		insert(v,u,w);
	}
	ll sum=0;
	if(dijkstra(1)){
		for(int i=1;i<=n;i++){
			sum+=(dst[i]*val[i]);
		}
		cout<<sum<<endl;
	}else{
		cout<<"No Answer"<<endl;
	}
	return 0;
} 


 

猜你喜欢

转载自blog.csdn.net/amf12345/article/details/89019469
今日推荐