hdu 4975 A simple Gaussian elimination problem 最大流+找环

原题链接

http://acm.hdu.edu.cn/showproblem.php?pid=4975

这是一道很裸的最大流,将每个点(i,j)看作是从Ri向Cj的一条容量为9的边,从源点除法连接每个Ri,再从每个Ci连接至汇点。如若最大流不是滿流,则问题无解。这道题的关键就是在于如何判断是否有多解。考虑这样一个事实,若残余网络上有多个点构成一个环,那么流量可在这个环上调整,某条边上多余的流量可以被环上的其他的边弥补回来。所以如果残余网络上存在一个边数大于2的环,那么问题则是多解。我判断是否有环的方法是Tarjan。

详见代码:

#include<iostream>
#include<stack>
#include<vector>
#include<cstring>
#include<algorithm>
#include<queue>
#define MAX_V 2015
#define MAX_N 10004
#define INF 2500005
using namespace std;

struct edge{int to,cap,rev;};

vector<edge> G[MAX_N];
int level[MAX_V];
int iter[MAX_V];

void add_edge(int from,int to,int cap) {
    G[from].push_back((edge) {to, cap, G[to].size()});
    G[to].push_back((edge) {from, 0, G[from].size() - 1});
}

void bfs(int s) {
    memset(level, -1, sizeof(level));
    queue<int> que;
    level[s] = 0;
    que.push(s);
    while (!que.empty()) {
        int v = que.front();
        que.pop();
        for (int i = 0; i < G[v].size(); i++) {
            edge &e = G[v][i];
            if (e.cap > 0 && level[e.to] < 0) {
                level[e.to] = level[v] + 1;
                que.push(e.to);
            }
        }
    }
}

int dfs(int v,int t,int f) {
    if (v == t)return f;
    for (int &i = iter[v]; i < G[v].size(); i++) {
        edge &e = G[v][i];
        if (e.cap > 0 && level[v] < level[e.to]) {
            int d = dfs(e.to, t, min(f, e.cap));
            if (d > 0) {
                e.cap -= d;
                G[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}

int max_flow(int s,int t) {
    int flow = 0;
    for (; ;) {
        bfs(s);
        if (level[t] < 0)return flow;
        memset(iter, 0, sizeof(iter));
        int f;
        while ((f = dfs(s, t, INF)) > 0) {
            flow += f;
        }
    }
}

bool vis[MAX_N];
int low[MAX_N],dfn[MAX_N],tot=0;
bool inStack[MAX_N];

stack<int> st;
bool exitCircle=false;

void Tarjan(int u) {
    if (exitCircle)return;
    vis[u] = 1;
    inStack[u] = 1;
    st.push(u);
    low[u] = dfn[u] = ++tot;
    for (int i = 0; i < G[u].size(); i++) {
        int v = G[u][i].to;
        if (G[u][i].cap == 0)continue;
        if (!vis[v]) {
            Tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if (inStack[v])
            low[u] = min(low[u], dfn[v]);
    }
    if (dfn[u] == low[u]) {
        int cnt = 0;
        while (inStack[u]) {
            if (st.empty())break;
            cnt++;
            //cout << st.top() << " ";
            inStack[st.top()] = 0;
            st.pop();
        }
        if (cnt > 2)exitCircle = true;
        //cout << endl;
    }
}

int T;
int N,M;

int main() {
    cin.sync_with_stdio(false);
    cin >> T;
    int cas = 0;
    while (T--) {

        int sum = 0;
        cin >> N >> M;

        for(int i=0;i<N+M+3;i++)G[i].clear();
        memset(vis,0,sizeof(vis));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        tot=0;
        memset(inStack,0,sizeof(inStack));
        exitCircle=false;
        while(st.size())st.pop();

        for (int i = 0; i < N; i++) {
            int a;
            cin >> a;
            sum += a;
            add_edge(0, i + 1, a);
        }
        for (int i = 0; i < M; i++) {
            int a;
            cin >> a;
            add_edge(N + i + 1, N + M + 1, a);
        }
        for (int i = 1; i <= N; i++)
            for (int j = 1; j <= M; j++)
                add_edge(i, j + N, 9);
        int flow = max_flow(0, N + M + 1);

        cout << "Case #" << ++cas << ": ";
        if (flow != sum) {
            cout << "So naive!" << endl;
            continue;
        }

        for (int i = 0; i <= N + M + 1; i++)if (!vis[i])Tarjan(i);
        if (exitCircle)cout << "So young!" << endl;
        else cout << "So simple!" << endl;
    }

    return 0;
}
原文地址:https://www.cnblogs.com/HarryGuo2012/p/4691001.html