题目描述大概是这样:
KCm要准备一颗圣诞树,这棵树有一些节点和边组成。节点从1到n,根总是1.每个节点都有自己的总量,而边的价格是由边的单价乘以子孙节点的重量。
求出这么一颗有n个节点的树,使花费最小。
思路:要求∑(边权子树点权和),等价于求∑(点权点到根路径上的边权和)。
第一道SPFA。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<string>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<stack>
#include<cmath>
#include<map>
#include<vector>
#define ll long long
#define inf 0x3f3f3f3f
#define bug1 cout<<"bug1"<<endl;
#define bug2 cout<<"bug2"<<endl;
#define bug3 cout<<"bug3"<<endl;
#define INF (1LL<<60)//自己错的原因还包括这里,要把INF弄得很大
using namespace std;
const int maxn=5*1e5+10;
int verw[2*maxn];
int n,e;
ll dist[2*maxn];
int head[2*maxn];
int vis[2*maxn];
struct Edge{
int v,nxt;
ll w;
}edge[2*maxn];
int tol;
void addedge(int u,int v,int w){
edge[tol].v=v;
edge[tol].w=w;
edge[tol].nxt=head[u];
head[u]=tol++;
}
queue<int>que;
int spfa(){
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;++i){
dist[i]=INF;
}
que.push(1);
dist[1]=0;
vis[1]=1;
while(!que.empty()){
int u=que.front();
que.pop();
for(int i=head[u];i!=-1;i=edge[i].nxt){
int v=edge[i].v;
if(dist[v]>dist[u]+edge[i].w){
dist[v]=dist[u]+edge[i].w;
if(vis[v]==0){
vis[v]=1;
que.push(v);
}
}
}
vis[u]=0;//没有这个会wa,想想是因为后面的点会到这个点,这个是最短路的基本知识了。。。。
}
for(int i=1;i<=n;++i)
if(dist[i]==INF)
return 0;
return 1;
}
void init(){
memset(verw,0,sizeof(verw));
memset(head,-1,sizeof(head));
tol=0;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
init();
scanf("%d%d",&n,&e);
for(int i=1;i<=n;++i){
scanf("%d",&verw[i]);
}
for(int i=1;i<=e;++i){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
}
if(spfa()==0){
printf("No Answer\n");
continue;
}
else{
ll ans=0;
for(int i=1;i<=n;++i){
ans+=dist[i]*verw[i];
}
cout<<ans<<'\n';
}
}
}