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
  • 相关阅读:
    《Effective Java》 读书笔记(三) 使用私有构造方法或枚举实现单例类
    《Effective Java》 读书笔记(二) 在构造参数过多的时候优先考虑使用构造器
    读书笔记-《Maven实战》-2018/5/3
    读书笔记-《Maven实战》-关于Maven依赖传递的思考 2018/4/26
    MySQL基础篇(07):用户和权限管理,日志体系简介
    SpringCloud微服务:Sentinel哨兵组件,管理服务限流和降级
    MySQL基础篇(06):事务管理,锁机制案例详解
    Java并发编程(02):线程核心机制,基础概念扩展
    SpringBoot2 整合ElasticJob框架,定制化管理流程
    Java基础篇(02):特殊的String类,和相关扩展API
  • 原文地址:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/9951711.html
Copyright © 2011-2022 走看看