1. 程式人生 > >51nod1443 路徑和樹

51nod1443 路徑和樹

題目
題解

容易想到先搞一遍單源最短路徑,然後只保留最短路徑上的邊,接下來容易想到最小生成樹,但是因為有的邊只刪了一個方向,所以變成了有向圖了,要求的就是最小樹形圖,比較麻煩而且容易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); }