zoukankan      html  css  js  c++  java
  • Codeforces1076D. Edge Deletion(最短路树+bfs)

    题目链接:传送门

    题目:

    D. Edge Deletion
    time limit per test
    2.5 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output
    
    You are given an undirected connected weighted graph consisting of n
    vertices and m edges. Let's denote the length of the shortest path from vertex 1 to vertex i as di
    
    .
    
    You have to erase some edges of the graph so that at most k
    edges remain. Let's call a vertex i good if there still exists a path from 1 to i with length di
    
    after erasing the edges.
    
    Your goal is to erase the edges in such a way that the number of good vertices is maximized.
    Input
    
    The first line contains three integers n
    , m and k (2≤n≤3105, 1≤m≤3105, n−1≤m, 0≤k≤m
    
    ) — the number of vertices and edges in the graph, and the maximum number of edges that can be retained in the graph, respectively.
    
    Then m
    lines follow, each containing three integers x, y, w (1≤x,y≤n, x≠y, 1≤w≤109), denoting an edge connecting vertices x and y and having weight w
    
    .
    
    The given graph is connected (any vertex can be reached from any other vertex) and simple (there are no self-loops, and for each unordered pair of vertices there exists at most one edge connecting these vertices).
    Output
    
    In the first line print e
    — the number of edges that should remain in the graph (0≤e≤k
    
    ).
    
    In the second line print e
    distinct integers from 1 to m
    
    — the indices of edges that should remain in the graph. Edges are numbered in the same order they are given in the input. The number of good vertices should be as large as possible.
    Examples
    Input
    Copy
    
    3 3 2
    1 2 1
    3 2 1
    1 3 3
    
    Output
    Copy
    
    2
    1 2 
    
    Input
    Copy
    
    4 5 2
    4 1 8
    2 4 1
    2 1 3
    3 4 9
    3 1 5
    
    Output
    Copy
    
    2
    3 2 
    View Code

    题目大意:

      一个图N个点M条双向边。设各点到点1的距离为di,保证满足条件删除M-K条边之后使得到点1的距离仍为di的点数量最多的情况下,输出剩余的K条边的编号(按输入顺序)。

       (2≤n≤3⋅105, 1≤m≤3⋅105, n−1≤m, 0≤k≤m)

    思路:

      用dijkstra跑出最短路树:

      松弛的时候用fat数组保存被松弛的点的父节点,用faEdge数组保存对应的边,这样就把整棵树保留下来了。

      然后在树上bfs,贪心地保留边就好了。(dfs、bfs都可以,反正是树,多一条边就多一个点)

    代码:

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int MAX_N = 3e5 + 5;
    
    int N, M, K;
    struct PQNode{
        int v;
        ll dis;
        PQNode(int _v = 0, ll _dis = 0) : v(_v), dis(_dis) {}
        bool operator < (const PQNode& x) const {
            return dis > x.dis;
        }
    };
    struct Edge{
        int id, v;
        ll w;
        Edge(int _id = 0, int _v = 0, ll _w = 0) : id(_id), v(_v), w(_w) {}
    };
    vector <Edge> E[MAX_N];
    void addEdge(int i, int u, int v, ll w) {
        E[u].push_back(Edge(i, v, w));
        E[v].push_back(Edge(i, u, w));
    }
    bool vis[MAX_N];
    ll dist[MAX_N];
    int fat[MAX_N], faEdge[MAX_N];
    priority_queue <PQNode> PQ;
    void Dijkstra()
    {
        memset(dist, 0x3f, sizeof dist);
        memset(vis, false, sizeof vis);
        dist[1] = 0;
        fat[1] = 1;
        PQ.push(PQNode(1, 0));
        while (!PQ.empty()) {
            int u = PQ.top().v;
            PQ.pop();
            if (vis[u])
                continue;
            vis[u] = true;
            for (int i = 0; i < (int)E[u].size(); i++) {
                int id = E[u][i].id;
                int v = E[u][i].v;
                ll w = E[u][i].w;
                if (vis[v])
                    continue;
                if (dist[v] > dist[u] + w) {
                    dist[v] = dist[u] + w;
                    fat[v] = u;
                    faEdge[v] = id;
                    PQ.push(PQNode(v, dist[v]));
                }
            }
        }
    }
    
    vector <int> son[MAX_N];
    queue <int> BQ;
    vector <int> ans;
    void bfs()
    {
        BQ.push(1);
        while (!BQ.empty() && K > 0) {
            int u = BQ.front(); BQ.pop();
            for (int i = 0; i < (int)son[u].size(); i++) {
                int v = son[u][i];
                if (K > 0) {
                    ans.push_back(faEdge[v]);
                    BQ.push(v);
                    K--;
                }
                else
                    break;
            }
        }
    }
    
    int main()
    {
        cin >> N >> M >> K;
        for (int i = 1; i <= M; i++) {
            int u, v; ll w;
            scanf("%d%d%lld", &u, &v, &w);
            addEdge(i, u, v, w);
        }
        Dijkstra();
        for (int i = 2; i <= N; i++)
            son[fat[i]].push_back(i);
        bfs();
        cout << ans.size() << endl;
        bool firstprint = true;
        for (int i = 0; i < (int)ans.size(); i++) {
            if (firstprint)
                firstprint = false;
            else
                printf(" ");
            printf("%d", ans[i]);
        }
        puts("");
        return 0;
    }
    /*
    3 3 2
    1 2 1
    3 2 1
    1 3 3
    */
    View Code

    比赛代码(改的模板,所以写的有点乱,待我回去整理一下)

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const ll INF = 0x3f3f3f3f3f3f3f3f;
    const int maxn = 3e5 + 5;
    struct qnode{
        int v;
        ll c;
        int cnt;
        qnode(int _v = 0, ll _c = 0, int _cnt = 0) : v(_v), c(_c), cnt(_cnt) {}
        bool operator < (const qnode& r) const {
            if (c == r.c)
                return cnt > r.cnt;
            return c > r.c;
        }
    };
    struct Edge{
        int v;
        int id;
        ll cost;
        Edge(int _v = 0, int _id = 0, ll _cost = 0) : v(_v), id(_id), cost(_cost) {}
    };
    vector <Edge> E[maxn];
    bool vis[maxn];
    ll dist[maxn];
    int cnt[maxn];
    int fa[maxn], faedge[maxn];
    //点的编号从 1 开始
    void Dijkstra(int N)
    {
        memset(vis, false, sizeof (vis));
        for (int i = 1; i <= N; i++)
            dist[i] = INF, cnt[i] = maxn;
        priority_queue <qnode> Q;
        dist[1] = 0;
        cnt[1] = 0;
        fa[1] = 1;
        Q.push(qnode(1, 0));
        qnode tmp;
        while (!Q.empty()) {
            tmp = Q.top(); Q.pop();
            int u = tmp.v;
            if (vis[u])
                continue;
            vis[u] = true;
            for (int i = 0; i < (int)E[u].size(); i++) {
                int v = E[u][i].v;
                ll cost = E[u][i].cost;
                int id = E[u][i].id;
                if (!vis[v]) {
                    if (dist[v] > dist[u] + cost) {
                        dist[v] = dist[u] + cost;
                        cnt[v] = cnt[u] + 1;
                        fa[v] = u;
                        faedge[v] = id;
                        Q.push(qnode(v, dist[v], cnt[v]));
                    }
                    else if (dist[v] == dist[u] + cost && cnt[v] > cnt[u] + 1) {
                        cnt[v] = cnt[u] + 1;
                        fa[v] = u;
                        faedge[v] = id;
                        Q.push(qnode(v, dist[v], cnt[v]));
                    }
                }
            }
        }
    }
    void addedge(int u, int v, ll w, int i) {
        E[u].push_back(Edge(v, i, w));
        E[v].push_back(Edge(u, i, w));
    }
    
    int N, M, K;
    vector <int> son[maxn];
    queue <int> BQ;
    vector <int> ans;
    
    void bfs() {
        BQ.push(1);
        while (!BQ.empty() && K > 0) {
            int u = BQ.front(); BQ.pop();
            int len = son[u].size();
            for (int i = 0; i < len; i++) {
                int v = son[u][i];
                if (K > 0) {
                    K--;
                    ans.push_back(faedge[v]);
                    BQ.push(v);
                }
                else
                    break;
            }
        }
    }
    
    int main() {
        cin >> N >> M >> K;
        for (int i = 1; i <= M; i++) {
            int u, v;
            ll w;
            scanf("%d%d%lld", &u, &v, &w);
            addedge(u, v, w, i);
        }
        Dijkstra(N);
        for (int i = 2; i <= N; i++) {
            son[fa[i]].push_back(i);
        }
        bfs();
        int len = ans.size();
        cout << len << endl;
        bool firstprint = true;
        for (int i = 0; i < len; i++) {
            if (firstprint)
                firstprint = false;
            else
                printf(" ");
            printf("%d", ans[i]);
        }
        puts("");
        return 0;
    }
    View Code
  • 相关阅读:
    函数配接器
    函数对象和函数指针
    unary_function 和 binary_function
    堆排序
    Shell排序
    volatile理解
    死锁
    进程间通信
    优化循环的方法-循环展开
    如何学习编译原理
  • 原文地址:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/9951711.html
Copyright © 2011-2022 走看看