• 「日常训练」Paths and Trees(Codeforces Round 301 Div.2 E)


    题意与分析

    题意是这样的,定义一个从某点出发的所有最短路方案中,选择边权和最小的最短路方案,称为最短生成树
    现在求一棵最短生成树,输出总边权和与选取边的编号。

    我们首先要明白这样一个结论:对一个图求Dijkstra后,把所有得到的最短路边全部连起来,生成的图一定是一棵树,是不会有环的。原因自己推一下就可以感受到。
    那么这样一来,这个树相当于我们在Dijkstra的时候就已经得到了。记录边是Dijkstra的基本操作,而我们只需要考虑一下当最短路相等时谁更优的情况并更新就可以了。

    代码

    #include <bits/stdc++.h>
    #define MP make_pair
    #define PB emplace_back
    #define fi first
    #define se second
    #define ZERO(x) memset((x), 0, sizeof(x))
    #define ALL(x) (x).begin(),(x).end()
    #define rep(i, a, b) for (repType i = (a); i <= (b); ++i)
    #define per(i, a, b) for (repType i = (a); i >= (b); --i)
    #define QUICKIO                  
        ios::sync_with_stdio(false); 
        cin.tie(0);                  
        cout.tie(0);
    using namespace std;
    using ll=long long;
    using repType=int;
    
    struct Edge
    {
        int u, v;
        ll w;
        Edge() {}
        Edge(int _u, int _v, ll _w): u(_u), v(_v), w(_w) {}
        bool
        operator < (const Edge& rhs) const
    	{
            if(w==rhs.w)
    			{ return (u==rhs.u)?v<rhs.v:u<rhs.u; }
            else { return w<rhs.w; }
        }
    };
    
    const int MAXN=300005;
    vector<Edge> edges;
    vector<int> G[MAXN];
    
    void
    add_edge(int u, int v, ll w)
    {
        edges.PB(u, v, w);
        G[u].PB(int(edges.size())-1);
    }
    
    ll dist[MAXN];
    int pre[MAXN]; // pre: last edge
    
    void
    dijkstra(int start)
    {
        memset(pre, -1, sizeof(pre));
        memset(dist, 0x3f, sizeof(dist));
        using P=pair<ll, int>;
        priority_queue<P, vector<P>, greater<> > pq; // <dist, pnt>: 大根堆
        dist[start]=0;
        pq.push(MP(0, start));
        while(!pq.empty())
        {
            auto now=pq.top(); pq.pop();
            int u=now.se;
            if(dist[u]<now.fi) { continue; }
            rep(i, 0, int(G[u].size())-1)
            {
                int v=edges[G[u][i]].v;
                ll  w=edges[G[u][i]].w;
                if(dist[v]>dist[u]+w)
                {
                    dist[v]=dist[u]+w;
                    pre[v]=G[u][i];
                    pq.push(MP(dist[v], v));
                }
                else if(dist[v]==dist[u]+w && edges[pre[v]].w>edges[G[u][i]].w)
    				{ pre[v]=G[u][i]; }
            }
        }
    }
    
    int
    main()
    {
    	int n, m;
        scanf("%d%d", &n, &m);
        rep(i, 1, m)
        {
            int u, v;
            ll w;
            scanf("%d%d%lld", &u, &v, &w);
            add_edge(u, v, w);
            add_edge(v, u, w);
        }
    
        int stp; scanf("%d", &stp);
        dijkstra(stp);
    
        ll ans=0;
        rep(i, 1, n) if(i!=stp) { ans+=edges[pre[i]].w; }
        printf("%lld
    ", ans);
        rep(i, 1, n) if(i!=stp) { printf("%d ", pre[i]/2+1); }
        printf("
    ");
    
        return 0;
    }
    
    如非注明,原创内容遵循GFDLv1.3发布;其中的代码遵循GPLv3发布。
  • 相关阅读:
    插入排序
    python -- 给电视剧重命名
    程序员你为什么迷茫?
    如何把自己打造成技术圈的 papi 酱
    GitHub中国区前100名到底是什么样的人?
    Python+opencv 图像拼接
    VS2015 新Web项目(C#6)出现CS1617错误的解决
    .Net Task<T>的一种比较神奇的卡死情况(Wait/Result卡死, await能得到结果)
    Xamarin Android自学和实践步骤
    跨过几个坑,终于完成了我的第一个Xamarin Android App!
  • 原文地址:https://www.cnblogs.com/samhx/p/cfr303d2e.html
Copyright © 2020-2023  润新知