枚举+求桥 Codeforces701F Break Up

来源:互联网 发布:小米手环数据修改攻略 编辑:程序博客网 时间:2024/04/26 06:31

传送门:点击打开链接

题意:最多删掉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;}


0 0
原创粉丝点击