[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");
 
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值