[BZOJ1797][AHOI2009][最大流][強連通分量]Mincut最小割

[Problem Description]
A,B兩個國家正在交戰,其中A國的物資運輸網中有N箇中轉站,M條單向道路。設其中第i (1≤i≤M)條道路連接了vi,ui兩個中轉站,那麼中轉站vi可以通過該道路到達ui中轉站,如果切斷這條道路,需要代價ci。現在B國想找出一個路徑切斷方案,使中轉站s不能到達中轉站t,並且切斷路徑的代價之和最小。 小可可一眼就看出,這是一個求最小割的問題。但愛思考的小可可並不侷限於此。現在他對每條單向道路提出兩個問題: 問題一:是否存在一個最小代價路徑切斷方案,其中該道路被切斷? 問題二:是否對任何一個最小代價路徑切斷方案,都有該道路被切斷? 現在請你回答這兩個問題。
[Algorithm]
最大流,強連通分量
[Analysis]
先跑最大流是肯定的。然後在殘留網絡裏跑強連通分量。一個原圖中的邊,如果滿流且兩點所在的強連通分量不同,則可能出現在最小割中,如果兩個強連通分量一個包含s,一個包含t,則一定出現在最小割中
[Pay Attention]
發現自己真是越來越手殘了……
[Code]
/**************************************************************
    Problem: 1797
    User: gaotianyu1350
    Language: C++
    Result: Accepted
    Time:452 ms
    Memory:6324 kb
****************************************************************/
 
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <queue>
using namespace std;
 
const long long MAXN = 5000;
const long long MAXM = 120100;
const long long INF  = ((unsigned long long)1<<63) - 1;
 
long long point[MAXN], nxt[MAXM], f[MAXM], v[MAXM], flow[MAXM], cap[MAXM];
long long lastedge[MAXN], deep[MAXN], num[MAXN], cur[MAXN];
long long tot, n, m, start, end;
 
bool check[MAXN];
 
long long dfsTime[MAXN] = {0}, lessTime[MAXN] = {0}, cct[MAXN] = {0}, st[MAXN] = {0};
long long nowTime = 0, cnt = 0, top = 0;
 
inline long long min(long long a, long long b)
{
    return a < b ? a : b;
}
 
inline long long max(long long a, long long b)
{
    return a > b ? a : b;
}
 
inline void clear()
{
    memset(point, -1, sizeof(point));
    memset(nxt, -1, sizeof(nxt));
    tot = -1;
}
 
inline void addedge(long long x, long long y, long long theCap)
{
    tot++;
    nxt[tot] = point[x];
    point[x] = tot;
    v[tot] = y;
    f[tot] =x;
    cap[tot] = theCap;
    tot++;
    nxt[tot] = point[y];
    point[y] = tot;
    v[tot] = x;
    f[tot] = y;
    cap[tot] = 0;
}
 
void bfs(long long s, long long t)
{
    queue<int> q;
    while (!q.empty()) q.pop();
    memset(check, 0, sizeof(check));
    memset(deep, 0, sizeof(deep));
    check[t] = true;
    q.push(t);
    while (!q.empty())
    {
        long long now = q.front();
        q.pop();
        for (long long temp = point[now]; temp != -1; temp = nxt[temp])
        {
            long long tt = temp ^ 1;
            if (!check[v[temp]] && flow[tt] < cap[tt])
            {
                check[v[temp]] = true;
                deep[v[temp]] = deep[now] + 1;
                q.push(v[temp]);
            }
        }
    }
}
 
inline long long addflow(long long s, long long t)
{
    long long ans = INF;
    long long now = t;
    while (now != s)
    {
        long long temp = lastedge[now];
        ans = min(ans, cap[temp] - flow[temp]);
        now = v[temp ^ 1];
    }
    now = t;
    while (now != s)
    {
        long long temp = lastedge[now];
        flow[temp] += ans;
        flow[temp ^ 1] -= ans;
        now = v[temp ^ 1];
    }
    return ans;
}
 
long long isap(long long s, long long t)
{
    long long ans = 0;
    long long now = s;
    bfs(s, t);
    memset(num, 0, sizeof(num));
    for (long long i = 1; i <= n; i++)
    {
        num[deep[i]]++;
        cur[i] = point[i];
    }
    while (deep[s] < n)
    {
        if (now == t)
        {
            ans += addflow(s, t);
            now = s;
        }
        bool isok = false;
        for (long long temp = cur[now]; temp != -1; temp = nxt[temp])
            if (deep[now] == deep[v[temp]] + 1 && flow[temp] < cap[temp])
            {
                isok = true;
                lastedge[v[temp]] = temp;
                cur[now] = temp;
                now = v[temp];
                break;
            }
        if (!isok)
        {
            long long minn = n - 1;
            for (long long temp = point[now]; temp != -1; temp = nxt[temp])
                if (flow[temp] < cap[temp])
                    minn = min(minn, deep[v[temp]]);
            if (--num[deep[now]] == 0) break;
            num[deep[now] = minn + 1]++;
            cur[now] = point[now];
            if (s != now) now = v[lastedge[now] ^ 1];
        }
    }
    return ans;
}
 
void tarjan(long long now)
{
    dfsTime[now] = lessTime[now] = ++nowTime;
    st[++top] = now;
    for (long long temp = point[now]; temp != -1; temp = nxt[temp])
        if (flow[temp] < cap[temp])
        {
            long long tar = v[temp];
            if (!dfsTime[tar])
            {
                tarjan(tar);
                lessTime[now] = min(lessTime[now], lessTime[tar]);
            }
            else if (!cct[tar])
                lessTime[now] = min(lessTime[now], dfsTime[tar]);
        }
    if (dfsTime[now] == lessTime[now])
    {
        cnt++;
        while (1)
        {
            cct[st[top--]] = cnt;
            if (st[top + 1] == now) break;
        }
    }
}
 
int main()
{
    //freopen("input.txt", "r", "stdin");
    clear();
    scanf("%lld%lld%lld%lld", &n, &m, &start, &end);
    for (long long i = 1; i <= m; i++)
    {
        long long x, y, z;
        scanf("%lld%lld%lld", &x, &y, &z);
        addedge(x, y, z);
    }
    isap(start, end);
    for (long long i = 1; i <= n; i++)
        if (!dfsTime[i])
            tarjan(i);
    for (long long i = 1; i <= m; i++)
    {
        long long now = i * 2 - 2;
        if (flow[now] == cap[now] && cct[f[now]] != cct[v[now]])
        {
            if (cct[f[now]] == cct[start] && cct[v[now]] == cct[end])
                printf("1 1\n");
            else
                printf("1 0\n");
        }
        else
            printf("0 0\n");
 
    }
}



發佈了52 篇原創文章 · 獲贊 0 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章