BZOJ 1797 AHOI 2009 Mincut 最小割 最小割

题目大意:给出一个网络图,求出这其中的可行边和必须边。


思路:看了策爷的博客,知道了两个结论:

最小割的必须边和可行边:

求最大流,在残余网络中求出SCC。若:

1.      对于任意一条满流边,有changed[x] != changed[y],则这个边为可行边。

2.      对于任意一条满流边,有changed[x] == changed[S] && changed[y]== changed[T],则这个边为必须边。

之后就是结论题了。


CODE:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 120010 
#define INF 0x3f3f3f3f
using namespace std;
 
int points,edges,S,T;
int head[MAX],total = 1;
int next[MAX << 1],aim[MAX << 1],from[MAX << 1],flow[MAX << 1];
 
int deep[MAX];
int dfn[MAX],changed[MAX],scc;
 
inline void Add(int x,int y,int f)
{
    next[++total] = head[x];
    aim[total] = y;
    from[total] = x;
    flow[total] = f;
    head[x] = total;
}
 
inline void Insert(int x,int y,int f)
{
    Add(x,y,f);
    Add(y,x,0);
}
 
inline bool BFS()
{
    static queue<int> q;
    while(!q.empty())   q.pop();
    memset(deep,0,sizeof(deep));
    deep[S] = 1;
    q.push(S);
    while(!q.empty()) {
        int x = q.front(); q.pop();
        for(int i = head[x]; i; i = next[i]) 
            if(flow[i] && !deep[aim[i]]) {
                deep[aim[i]] = deep[x] + 1;
                q.push(aim[i]);
                if(aim[i] == T) return true;
            }
    }
    return false;
}
 
int Dinic(int x,int f)
{
    if(x == T)  return f;
    int temp = f;
    for(int i = head[x]; i; i = next[i])
        if(flow[i] && deep[aim[i]] == deep[x] + 1 && temp) {
            int away = Dinic(aim[i],min(temp,flow[i]));
            if(!away)   deep[aim[i]] = 0;
            flow[i] -= away;
            flow[i^1] += away;
            temp -= away;
        }
    return f - temp;
}
 
void Tarjan(int x)
{
    static int low[MAX],total;
    static int stack[MAX],top;
    static bool in_stack[MAX];
    dfn[x] = low[x] = ++total;
    stack[++top] = x;
    in_stack[x] = true;
    for(int i = head[x]; i; i = next[i])
        if(flow[i]) {
            if(!dfn[aim[i]])
                Tarjan(aim[i]),low[x] = min(low[x],low[aim[i]]);
            else if(in_stack[aim[i]])
                low[x] = min(low[x],dfn[aim[i]]);
        }
    if(low[x] == dfn[x]) {
        ++scc;
        int temp;
        do {
            temp = stack[top--];
            in_stack[temp] = false;
            changed[temp] = scc;
        }while(temp != x);
    }
}
 
int main()
{
    cin >> points >> edges >> S >> T;
    for(int x,y,z,i = 1; i <= edges; ++i) {
        scanf("%d%d%d",&x,&y,&z);
        Insert(x,y,z);
    }
    while(BFS())
        Dinic(S,INF);
    for(int i = 1; i <= points; ++i)
        if(!dfn[i]) Tarjan(i);
    for(int i = 2; i <= edges << 1; i += 2) {
        if(!flow[i]) {
            if(changed[from[i]] != changed[aim[i]])
                printf("1 ");
            else    printf("0 ");
            if(changed[S] == changed[from[i]] && changed[T] == changed[aim[i]])
                puts("1");
            else    puts("0");
        }
        else    puts("0 0");
    }
    return 0;
}


你可能感兴趣的:(最小割,网络流,最大流,bzoj,jcvb)