CodeForces #303E Div.2 Paths and Trees(最短路+拓扑排序)

来源:互联网 发布:高阶矩阵求逆 编辑:程序博客网 时间:2024/05/16 05:45

果然题目写完不抓紧写博客就全部都不记得还得把题目先理一遍。

题目链接:http://codeforces.com/problemset/problem/545/E


题目大意:求给定图的一颗最小最短路生成树,最小最短路生成树满足的条件是以顶点1为根的一棵生成树,从1到所有点的路径长度全是原无向图中的最短路长度,在所有的符合条件的树中找到代价最小的,输出边的编号。

如果单纯考虑求最短路,然后记录路径未必是满足条件,比如edge[1][3] = 2, edge[1][2] = 1, edge[2][3] = 1,这样1到3的距离可以是直接距离,也可以是间接距离。但是如果要代价最小,肯定选择间接距离。

考虑到这种情况,我们先计算最短路,但是不计算更新路径。枚举所有的边,找出所有与最短路的不冲突的入边,并计算同时点的入度。最后用拓扑排序寻找最小代价的邻接边,然后将对应的边加入集合中,然后删去这个顶点。(这个过程需要多想几遍才好理解)。


代码如下:

#include <bits/stdc++.h>using namespace std;typedef long long LL;const LL oo = INT_MAX;const LL maxn = 300005;struct N {    int v;    LL dis;    N(int a, LL b): v(a), dis(b) {}    bool operator < (const N& other) const {        return dis > other.dis;    }};struct E {    int to;    LL cost;    int next;};E edge[2 * maxn];int head[maxn];LL dist[maxn];int vis[maxn];int indeg[maxn];vector<LL> inarr[maxn];LL n, m, s;int eid = 1;vector<LL> arr;void addEdge(int from, int to, int cost) {    edge[eid].to = to;    edge[eid].cost = cost;    edge[eid].next = head[from];    head[from] = eid ++;}void dij(int s) {    for (int i = 1; i <= n; i ++) {        vis[i] = false;        dist[i] = oo;    }    priority_queue<N> que;    dist[s] = 0;    que.push(N(s, (LL)0));    while (!que.empty()) {        N cur = que.top();        que.pop();        if(vis[cur.v]) {            continue;        }        vis[cur.v] = 1;        for (int j = head[cur.v]; ~j; j = edge[j].next) {            int e = edge[j].to;            if(dist[e] >= edge[j].cost + cur.dis || dist[e] == oo) {                dist[e] = edge[j].cost + cur.dis;                que.push(N(e, dist[e]));            }        }    }}void topo(int s) {    LL ans = 0;    queue<int> q;    q.push(s);    //队列中元素为入度为0的点,这些点的前驱必定已经加入树的集合    while(!q.empty()) {        int cur = q.front();        q.pop();        int len = inarr[cur].size();        if(len > 0) {            int minEdge = oo, pos = -1;            for (int i = 0; i < len; i ++) {                int id = inarr[cur][i];                if(minEdge > edge[id].cost) {                    minEdge = edge[id].cost;                    pos = id;                }            }            ans += minEdge;            arr.push_back((pos + 1) >> 1);        }        for (int i = head[cur]; ~i; i = edge[i].next) {            if(dist[edge[i].to] == dist[cur] + edge[i].cost) {                indeg[edge[i].to] --;                if(indeg[edge[i].to] == 0) {                    q.push(edge[i].to);                }            }        }    }    printf("%I64d\n",ans);    int arrlen = arr.size();    for (int i = 0; i < arrlen; i ++) {        printf("%I64d ", arr[i]);    }}int main() {    scanf("%I64d%I64d", &n, &m);    int i = 1;    int from, to, cost;    memset(head, -1, sizeof(head));    while(i <= m) {        scanf("%d%d%d", &from, &to, &cost);        addEdge(from, to, cost);        addEdge(to, from, cost);        i ++;    }    scanf("%I64d", &s);    dij(s);    for (int i = 1; i <= n; i ++) {        for (int j = head[i]; ~j; j = edge[j].next) {            if(dist[edge[j].to] == dist[i] + edge[j].cost) {                indeg[edge[j].to] ++;           //所有点符合最短路的入度                inarr[edge[j].to].push_back(j); //所有点符合最短路的边列表            }        }    }    topo(s);    return 0;}

0 0
原创粉丝点击