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);
}

猜你喜欢

转载自blog.csdn.net/xumingyang0/article/details/81014078
今日推荐