1. 程式人生 > >列舉+求橋 Codeforces701F Break Up

列舉+求橋 Codeforces701F Break Up

題意:最多刪掉2條邊,使得無向圖中s到t不連通。點數<=1e3,邊數<=3e4

思路:我們先求一條s到t的任意路徑。
我們很容易就能證明,如果存在這樣的2條邊,或者說只需要刪一條邊就能讓他們兩個不連通,那麼必然是在s到t的一條路徑上。
所以,我們首先求出任意一條s到t的路徑。
然後列舉這條路徑上的邊,最多也只有n-1條。
列舉完後,把這條邊刪了,求橋,而且這個橋必須要滿足,S和T分別在橋的兩端。
我們可以這樣來判斷這種橋是否存在。
首先我們從S開始tarjan,當我們列舉u的一條邊e,另一個點是v時候,發現DFN[u]<Low[v],說明這條邊是橋,然後我們又發現DFN[v]<=DFN[T],T表示終點,此時就說明,T和v在橋的相同一側,也就是說T和S就恰好分別在橋的兩邊了。
找到這樣的橋後,再和我們之前列舉刪除的邊的權值加起來組合更新答案即可。
我通常對於這種方案比較複雜的,寫一個Ans的結構體,之後維護方案感覺方便的多

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout<<"["<<x<<"]";
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("input.txt","w+",stdout);
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;

const int MX = 1e3 + 5;
const int INF = 0x3f3f3f3f;

struct Edge {
    int u, v, nxt, cost;
} E[200005];
int n, m, S, T, dfn, del, ans1, ansid;
int Head[MX], erear;
int DFN[MX], Low[MX];
void edge_init() {
    erear = 0;
    memset(Head, -1, sizeof(Head));
}
void edge_add(int u, int v, int cost) {
    E[erear].u = u;
    E[erear].v = v;
    E[erear].cost = cost;
    E[erear].nxt = Head[u];
    Head[u] = erear++;
}
inline int read() {
    char c = getchar();
    while(!isdigit(c)) c = getchar();

    int x = 0;
    while(isdigit(c)) {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x;
}

class Path {
public:
    bool vis[MX];
    int S[MX], E[MX], fa[MX], sz;
    void solve() {
        sz = 0;
        memset(vis, 0, sizeof(vis));

        queue<int>Q;
        Q.push(::S); vis[::S] = 1;
        fa[::S] = -1;

        bool ok = 0;
        int u, v;
        while(!Q.empty()) {
            u = Q.front(); Q.pop();
            if(u == T) {
                ok = 1; break;
            }
            for(int i = Head[u]; ~i; i =::E[i].nxt) {
                v =::E[i].v;
                if(vis[v]) continue;
                Q.push(v); vis[v] = 1;
                fa[v] = u; E[v] = (i + 2) / 2;
            }
        }
        if(!ok) return;
        u = T;
        while(fa[u] != -1) {
            S[++sz] = E[u];
            u = fa[u];
        }
    }
} path;
struct Ans {
    int id[2];
    int num, totcost;
    Ans() {
        num = 0;
        totcost = 2 * INF;
    }
    void print() {
        if(totcost == 2 * INF) printf("-1\n");
        else {
            printf("%d\n%d\n", totcost, num);
            for(int i = 0; i < num; i++) printf("%d ", id[i]);
        }
    }
};

int P[MX];
int find(int x) {
    return P[x] == x ? x : (P[x] = find(P[x]));
}
void tarjan(int u, int e) {
    Low[u] = DFN[u] = ++dfn;
    for(int i = Head[u]; ~i; i = E[i].nxt) {
        if((i + 2) / 2 == del) continue;
        int v = E[i].v;
        if(!DFN[v]) {
            tarjan(v, i | 1);
            Low[u] = min(Low[u], Low[v]);
            if(Low[v] > DFN[u] && DFN[v] <= DFN[T] && ans1 > E[i].cost) {
                ansid = (i + 2) / 2;
                ans1 = E[i].cost;
            }
        } else if((i | 1) != e && DFN[v] < DFN[u]) {
            Low[u] = min(Low[u], DFN[v]);
        }
    }
}
void find_bridge() {
    ans1 = INF;
    dfn = 0;
    memset(DFN, 0, sizeof(DFN));
    tarjan(S, -1);
}
int main() {
    //FIN;
    edge_init();
    scanf("%d%d", &n, &m);
    scanf("%d%d", &S, &T);
    for(int i = 1; i <= n; i++) P[i] = i;
    for(int i = 1; i <= m; i++) {
        int u = read(), v = read(), cost = read();
        edge_add(u, v, cost);
        edge_add(v, u, cost);
        int p1 = find(u), p2 = find(v);
        P[p1] = p2;
    }

    if(find(S) != find(T)) {
        printf("0\n0\n");
        return 0;
    }

    Ans ans;
    path.solve();

    find_bridge();
    if(ans1 != INF) {
        ans.num = 1;
        ans.totcost = ans1;
        ans.id[0] = ansid;
    }

    for(int i = 1; i <= path.sz; i++) {
        del = path.S[i]; //uck(del);
        find_bridge();
        //printf("[%d,%d] %d\n", del, ansid, ans);
        if(ans1 != INF && ans1 + E[(del - 1) * 2].cost < ans.totcost) {
            ans.num = 2;
            ans.id[0] = ansid; ans.id[1] = del;
            ans.totcost = ans1 + E[(del - 1) * 2].cost;
        }
    }
    ans.print();
    return 0;
}