大意:给定一个图(多汇点,一个流入点),问能改变哪些边的流量使得原网络的流增加。

思路:求网络流里的关键边,关键边一是最小割集上的子集。

它具有如下性质:

1、满流;

2、源点可以通过残余网络(残余量不为0)访问到该边的起始点u;

3、汇点可以通过残余网络(残余量不为0)访问到该边的终点v;

求出网络流后,2次dfs求出所有标记即可,如果该边满流且起点、终点都被标记,则说明该边是关键边。

 

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <map>
using namespace std;
 
struct Edge
{
    int from, to, cap, flow;
    Edge(int from, int to, int cap, int flow): from(from), to(to), cap(cap), flow(flow) {}
};
 
const int maxn = 105;
const int INF = 0x3f3f3f3f;
 
struct ISAP
{
    int n, m, s, t;
    vector<Edge> edges;
    vector<int> G[maxn];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];
    int p[maxn];
    int num[maxn];
     
    bool vis1[maxn], vis2[maxn];
     
    void init(int n)
    {
        this->n = n;
        for(int i = 0; i < n; i++) G[i].clear();
        edges.clear();
        memset(vis1, 0, sizeof(vis1));
        memset(vis2, 0, sizeof(vis2));
    }
     
    void AddEdge(int from, int to, int cap)
    {
        edges.push_back(Edge (from, to, cap, 0));
        edges.push_back(Edge (to, from, 0, 0));
        m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }
     
    void ClearFlow()
    {
        for(int i = 0; i < edges.size(); i++) edges[i].flow = 0;
    }
     
    bool bfs()
    {
        memset(vis, 0, sizeof(vis));
        queue<int> Q;
        Q.push(t);
        d[t] = 0;
        vis[t] = 1;
        while(!Q.empty())
        {
            int x = Q.front(); Q.pop();
            for(int i = 0; i < G[x].size(); i++)
            {
                Edge&e = edges[G[x][i]^1];
                if(!vis[e.from] && e.cap > e.flow)
                {
                    vis[e.from] = 1;
                    d[e.from] = d[x] + 1;
                    Q.push(e.from);
                }
            }
        }
        return vis[s];
    }
     
    int Augment()
    {
        int x = t, a = INF;
        while(x != s)
        {
            Edge&e = edges[p[x]];
            a = min(a, e.cap-e.flow);
            x = edges[p[x]].from;
        }
        x = t;
        while(x != s)
        {
            edges[p[x]].flow += a;
            edges[p[x]^1].flow -= a;
            x = edges[p[x]].from;
        }
        return a;
    }
     
    int MaxFlow(int s, int t)
    {
        this->s = s; this->t = t;
        int flow = 0;
        bfs();
        memset(num, 0, sizeof(num));
        for(int i = 0; i < n; i++) num[d[i]]++;
        int x = s;
        memset(cur, 0, sizeof(cur));
        while(d[s] < n)
        {
            if(x == t) { flow += Augment(); x = s; }
            int ok = 0;
            for(int& i = cur[x]; i < G[x].size(); i++)
            {
                Edge&e = edges[G[x][i]];
                if(e.cap > e.flow && d[x] == d[e.to]+1)
                {
                    ok = 1;
                    p[e.to] = G[x][i];
                    cur[x] = i;
                    x = e.to;
                    break;
                }
            }
            if(!ok)
            {
                int m = n-1;
                for(int i = 0; i < G[x].size(); i++)
                {
                    Edge&e = edges[G[x][i]];
                    if(e.cap > e.flow) m = min(m, d[e.to]);
                }
                if(--num[d[x]] == 0) break;
                num[d[x] = m+1]++;
                cur[x] = 0;
                if(x != s) x = edges[p[x]].from;
            }
        }
        return flow;
    }
       
    void dfs1(int u)
    {
        vis1[u] = 1;
            for(int i = 0; i < G[u].size(); i++)
        {
            Edge&e = edges[G[u][i]];
            if(!vis1[e.to] && e.cap - e.flow > 0)
            {
                dfs1(e.to);
            }
        }
    }
 
    void dfs2(int u)
    {
        vis2[u] = 1;
        for(int i = 0; i < G[u].size(); i++)
        {
            Edge &e = edges[G[u][i]^1];
            if(!vis2[e.from] && e.cap > e.flow)
            {
                dfs2(e.from);
            }
        }
    }
};
 
ISAP solver;
int n, m, L;
int s, t;
 
int read_case()
{
    scanf("%d%d%d", &n, &m, &L);
    if(!n) return 0;
    solver.init(n+m+3);
    for(int i = 0; i < L; i++)
    {
        int from, to, cap;
        scanf("%d%d%d", &from, &to, &cap);
        solver.AddEdge(from, to, cap);
    }
    s = n+m+1, t = 0;
    for(int i = 1; i <= n; i++) solver.AddEdge(s, i, INF);
    solver.MaxFlow(s, t);
    return 1;
}
 
void solve()
{
    solver.dfs1(s);
    solver.dfs2(t);
    int first = 1;
    for(int i = 0; i < solver.m; i+=2)
    {
        Edge&e = solver.edges[i];
        if(solver.vis1[e.from] && solver.vis2[e.to] && e.cap == e.flow)
        {
            if(first) { printf("%d", i/2+1); first = 0;}
            else printf(" %d", i/2+1);
        }
    }
    if(first) printf("\n");
    printf("\n");
}
 
int main()
{
    while(read_case())
    {
        solve();
    }
    return 0;
}
View Code

 

 

 

posted on 2013-05-18 14:03  Buck Meister  阅读(155)  评论(0编辑  收藏  举报