51nod1443 路徑和樹
阿新 • • 發佈:2019-02-16
容易想到先搞一遍單源最短路徑,然後只保留最短路徑上的邊,接下來容易想到最小生成樹,但是因為有的邊只刪了一個方向,所以變成了有向圖了,要求的就是最小樹形圖,比較麻煩而且容易T
實際上,考慮在連好的圖裡加一個點,肯定是加連向它的最短邊,類似貪心的思路,所以結果就是刪完後的圖中,每個點的最小前驅邊權的和。
#include<bits/stdc++.h>
using namespace std;
const int N=300002;
typedef long long ll;
struct node{
int to,ne,w;
}e[N<<1];
int n,m,i,x,y,s,u,vis[N],tot,h[N],v,z,pre[N];
queue<int>q;
ll dis[N],ans;
inline char gc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline int read(){
int x=0,fl=1;char ch=gc();
for (;ch<48 ||ch>57;ch=gc())if(ch=='-')fl=-1;
for (;48<=ch&&ch<=57;ch=gc())x=(x<<3)+(x<<1)+(ch^48);
return x*fl;
}
void add(int x,int y,int z){
e[++tot]=(node){y,h[x],z};
h[x]=tot;
}
int main(){
n=read();m=read();
for (i=1;i<=m;i++) x=read(),y=read(),z=read(),add(x,y,z),add(y,x,z);
s=read();
memset (dis,63,sizeof(dis));
q.push(s);dis[s]=0;
while (!q.empty()){
u=q.front();q.pop();vis[u]=0;
for (i=h[u];i;i=e[i].ne){
v=e[i].to;
if (dis[u]+e[i].w<dis[v]){
dis[v]=dis[u]+e[i].w;
pre[v]=e[i].w;
if (!vis[v]) vis[v]=1,q.push(v);
}else if (dis[u]+e[i].w==dis[v]) pre[v]=min(pre[v],e[i].w);
}
}
for (i=1;i<=n;i++) ans+=pre[i];
printf("%lld",ans);
}