zoukankan      html  css  js  c++  java
  • codeforces 567 E. President and Roads dijkstra + 求图的桥

    题意:

    给出一个图,n <= 10^5,给出起点s和终点t

    有向边,每花费一个单位的钱可以选择一条边,把它的边权-1,但是边权必须>0,

    比如边权为w,最多花费w-1,边权变为1,但是不能把边权变为0

    现在要选择一条最短路从s到t

    题目保证s到t至少有一条路

    问这个图

    1.哪些边是一定会经过的

    2.哪些边是可以改变边权使得它一定会经过的,最少花费多少?

    3.哪些边是无论怎么改变边权,都不满足一定会经过的

    先跑一遍dijkstra,求出ds数组,ds[i]表示s到i的最短距离

    再把边的方向反过来,求出dt数组,dt[i]表示t到i的最短距离

    对于1

    一条边一定会经过,说明每一条最短路都经过它,那么我们把所有的最短路的边拿出来,建一个新图,新图的桥就是一定会经过的边

    那怎么判断边e=(u,v,w)是否属于某一条最短路呢?

    如果e属于某一条最短路,一定有:

    ds[u] + w + dt[v] = ds[t]

    问题1解决

    对于2

    一条边e=(u,v,w)修改后,一定会经过它,假设修改边权花费了x:

    则有:ds[u] + w - x + dt[v] = ds[t] - 1

    并且:w - x > 0

    即:x = ds[u] + w + dt[v] - ds[t] + 1

    且:x < w

    对于3

    除了1的边和2的边,其余的边都属于3

    这道题,本来不难,但是没有考虑2个点,debug 了好久

    1.图没有自环,但是有多重边,在求图的桥的时候没有处理多重边,wa 12

    2.新建的最短路图,在求桥的时候,我是调用了tagjan(1),表示从节点1开始处理,

    但是对于这个新图,1可能没有和s,t在同一个联通块(题目保证s到t有路径,则s和t一定在一个联通块),wa 59

    应该是调用tarjan(s)或者targan(t)

    代码:

                                                
      //File Name: cf567E.cpp
      //Created Time: 2017年08月30日 星期三 18时45分21秒
                                       
    #include <bits/stdc++.h>
    #define LL long long
    #define pii pair<int,int>
    #define pli pair<LL,int>
    #define fir first
    #define sec second
    using namespace std;
    const int MAXN = 100000 + 5;
    const LL INF = 100000000000000;
    struct Edge{
        int from,to,cost;
    };
    Edge edge[MAXN];
    LL ds[MAXN],dt[MAXN];//ds[i],dt[i]分别表示i到s,t的最短距离
    vector<int> G[MAXN]; //G[u]保存edge中from=u的边的id,即在edge中的位置
    bool bridge[MAXN];   //第i条边在最短路图中是bridge,则bridge[i] = true
    
    void clear_G(const int n){
        for(int i(1);i<=n;++i)
            G[i].clear();
    }
    priority_queue<pli> que;
    bool vis[MAXN];
    void dijkstra(const int n,const int m,const int s,LL *ds,const bool rev){
        for(int i(1);i<=n;++i)
            ds[i] = INF;
        ds[s] = 0;
        memset(vis,false,sizeof vis);
        while(!que.empty()) que.pop();
        que.push(pli(0,s));
        while(!que.empty()){
            pli tmp = que.top();
            que.pop();
            int u(tmp.sec);
            LL dis(-tmp.fir);
            if(vis[u] || dis != ds[u]) continue;
            vis[u] = true;
            for(auto cur:G[u]){
                int v;
                if(rev) v = edge[cur].from;
                else v = edge[cur].to;
                int w(edge[cur].cost);
                if(!vis[v] && ds[v] > ds[u] + w){
                    ds[v] = ds[u] + w;
                    que.push(pli(-ds[v],v));
                }
            }
        }
    }
    int dfs_clock;
    int pre[MAXN];
    int low[MAXN];
    void dfs(const int u,const int fa){
        low[u] = pre[u] = ++dfs_clock;
        bool flag = false;
        for(auto cur:G[u]){
            int v = edge[cur].to;
            if(v == u) v = edge[cur].from;
            if(v == fa && !flag){
                flag = true;
                continue;
            }
            if(!pre[v]){
                dfs(v,u);
                low[u] = min(low[v],low[u]);
                if(low[v] > pre[u])
                    bridge[cur] = true;
            }
            else if(pre[v] < low[u])
                low[u] = pre[v];
        }
    }
    void find_bridge(const int n,const int s){
        dfs_clock = 0;
        memset(pre,0,sizeof pre);
        memset(low,0,sizeof low);
        memset(bridge,false,sizeof bridge);
        dfs(s,0);
    }
    void solve(const int n,const int m,const int s,const int t){
        clear_G(n);
        for(int i(1);i<=m;++i)
            G[edge[i].from].push_back(i);
        dijkstra(n,m,s,ds,false);
        clear_G(n);
        for(int i(1);i<=m;++i)
            G[edge[i].to].push_back(i);
        dijkstra(n,m,t,dt,true);
        clear_G(n);
        for(int i(1);i<=m;++i){
            int u(edge[i].from),v(edge[i].to),w(edge[i].cost);
            if(ds[u] + dt[v] + w == ds[t]){
                G[u].push_back(i);
                G[v].push_back(i);
            }
        }
        find_bridge(n,s);
        for(int i(1);i<=m;++i){
            int u(edge[i].from),v(edge[i].to),w(edge[i].cost);
            if(ds[u] + dt[v] + w == ds[t]){
                if(bridge[i]) puts("YES");
                else if(w > 1) puts("CAN 1");
                else puts("NO");
            }
            else{
                LL cur = ds[u] + dt[v] + w - ds[t] + 1;
                if(w - cur > 0)
                    printf("CAN %lld
    ",cur);
                else
                    puts("NO");
            }
        }
    }
    int main(){
        int n,m,s,t;
        scanf("%d %d %d %d",&n,&m,&s,&t);
        for(int i(1),u,v,w;i<=m;++i){
            scanf("%d %d %d",&u,&v,&w);
            edge[i].from = u;
            edge[i].to = v;
            edge[i].cost = w;
        }
        solve(n,m,s,t);
        return 0;
    }

     

  • 相关阅读:
    Linux下NDK编译FFMPEG包含neon参数
    编译器优化陷阱——全局指针多次使用异常
    Linux下使用NDK编译FFMPEG(libstagefright)
    查看Android支持的硬解码信息
    图片格式转换
    转 MFC 主界面函数中线程等待避免界面卡死的处理方法
    Windows Shell编程实现重叠图标IconOverlay
    转 MFC中 GB2312、UTF-8、unicode 之间转换
    windows双机调试
    位图BITMAP结构
  • 原文地址:https://www.cnblogs.com/-maybe/p/7456305.html
Copyright © 2011-2022 走看看