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\n",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;
}

 

 

 

 

 

 

 

 

 

posted on 2017-08-31 02:05  _fukua  阅读(246)  评论(0编辑  收藏  举报