codeforces 567 E. President and Roads dijkstra + 求圖的橋

題意:c++

給出一個圖,n <= 10^5,給出起點s和終點t數組

有向邊,每花費一個單位的錢能夠選擇一條邊,把它的邊權-1,可是邊權必須>0,spa

好比邊權爲w,最多花費w-1,邊權變爲1,可是不能把邊權變爲0debug

如今要選擇一條最短路從s到tcode

題目保證s到t至少有一條路blog

問這個圖it

1.哪些邊是必定會通過的io

2.哪些邊是能夠改變邊權使得它必定會通過的,最少花費多少?class

3.哪些邊是不管怎麼改變邊權,都不知足必定會通過的bug

 

先跑一遍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;
}
相關文章
相關標籤/搜索