2016 Russian Code Cup (RCC 16), Final Round B - Cactusophobia

B - Cactusophobia

思路:

点双联通分量+最大流

用tarjan求出每个点双联通分量

对于大小大于1的点双联通分量,它就是个环,那么源点和这个环相连,

容量为环的大小减一,这个环和环上的颜色连边,容量为一;

对于大小为1的点双连通分量,它只有一条边,那么源点和这个分量连边,

分量和边上颜色连边,容量都为1

然后所有颜色和汇点连边,容量为1

最后跑一遍最大流就可以了

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define mem(a, b) memset(a, b, sizeof(a))
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout);
//head

const int N = 1e4 + 5, M = 4e4 + 25;
const int INF = 0x7f7f7f7f;
vector<pii> G[N];
vector<int> bcc[N*2];
int color[N*2];
int low[N], dfn[N], stk[N*2], tot = 0, top = 0, cnt = 0;
int level[M], iter[M];
struct edge {
    int to, w, rev;
};
vector<edge>g[M];
void add_edge(int u, int v, int w) {
    g[u].pb(edge{v, w, g[v].size()});
    g[v].pb(edge{u, 0, g[u].size()-1});
}
void bfs(int s) {
    mem(level, -1);
    queue<int>q;
    level[s] = 0;
    q.push(s);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int i = 0; i < g[u].size(); i++) {
            edge e = g[u][i];
            if(e.w > 0 && level[e.to] < 0) {
                level[e.to] = level[u] + 1;
                q.push(e.to);

            }
        }
    }
}
int dfs(int u, int t, int f) {
    if(u == t ) return f;
    for (int &i = iter[u]; i < g[u].size(); i++) {
        edge &e = g[u][i];
        if(e.w > 0 && level[u] < level[e.to]) {
            int d = dfs(e.to, t, min(f, e.w));
            if(d > 0) {
                e.w -= d;
                g[e.to][e.rev].w +=d;
                return d;
            }
        }
    }
    return 0;
}
int max_flow(int s, int t) {
    int flow = 0;
    while(true) {
        bfs(s);
        if(level[t] < 0) return flow;
        int f;
        mem(iter, 0);
        while ((f = dfs(s, t, INF)) > 0) {
            flow += f;
        }
    }
}
void tarjan(int u, int fa) {
    low[u] = dfn[u] = ++tot;
    for (pii p : G[u]) {
        int v = p.fi;
        if(v == fa) continue;
        if(!dfn[v]) {
            stk[++top] = p.se;
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if(low[v] >= dfn[u]) {
                cnt++;
                while(stk[top] != p.se) bcc[cnt].pb(stk[top--]);
                bcc[cnt].pb(stk[top--]);
            }
        }
        else if(dfn[v] < dfn[u]) {
            stk[++top] = p.se;
            low[u] = min(low[u], dfn[v]);
        }
    }
}
int main() {
    int n, m, u, v, c;
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= m; i++) {
        scanf("%d %d %d", &u, &v, &color[i]);
        G[u].pb(pii{v, i});
        G[v].pb(pii{u, i});
    }
    tarjan(1, 1);
     int s = 0, t = cnt+m+1;
    for (int i = 1; i <= cnt; i++) {
        if(bcc[i].size() == 1)add_edge(s, i, 1);
        else add_edge(s, i, bcc[i].size()-1);
    }
    for (int i = 1; i <= cnt; i++) {
        for (int j : bcc[i]) {
            add_edge(i, cnt+color[j], 1);
        }
    }
    for (int i = 1; i <= m; i++) add_edge(cnt+i, t, 1);
    printf("%d\n", max_flow(s, t));
    return 0;
}

 

posted @ 2018-12-08 22:35  Wisdom+.+  阅读(356)  评论(0编辑  收藏  举报