zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    [Effective Java读书笔记] 第二章 创建和销毁对象(1~7)
    [Guava官方文档翻译] 5. Guava的Object公共方法 (Common Object Utilities Explained)
    [Guava官方文档翻译] 4. 使用Guava Ordering排序 (Ordering Explained)
    iOS正则表达式
    ios UIKit动力
    iOS8 UISearchViewController搜索功能讲解
    APP被苹果APPStore拒绝的各种原因
    iOS tableViewCell plane格式下,接近section边缘不显示分割线却被复用解决办法
    企业证书APP发布流程
    iOS越狱包
  • 原文地址:https://www.cnblogs.com/HarryGuo2012/p/4691001.html
Copyright © 2011-2022 走看看