版权声明:原创博客 喜欢拿走 https://blog.csdn.net/qq_43004519/article/details/88851807
题目描述
圣诞节快到了,蒜头君准备做一棵大圣诞树。
这棵树被表示成一组被编号的结点和一些边的集合,树的结点从 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 }
文章来源: https://blog.csdn.net/qq_43004519/article/details/88851807