ZOJ - 2532 Internship (网络流求割边)

题目链接

有n个城市和m个中转点,0号点是汇点。问提高哪一条边的容量可以使进入汇点的容量增加。

如果一条边对总的流量有影响,那么它在求完最大流的残余网络中肯定满足两个条件:第一,这条边是满流;第二,源点和汇点分别经过未满流的边可达此边的两个端点。

因此就是求最大流后在残余网络中dfs处理一下连通性,然后遍历每一条边判断即可。

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;

const int maxn = 205;
const int maxm = 100050;
const int INF = 0x3f3f3f3f;

int n, m, k, a, b, x, no, head[maxn], q[maxm];
int sta[maxn], gap[maxn], cur[maxn], level[maxn];
bool vis[maxn][2];
vector<int>ans;
struct node
{
    int from, to, nxt, id;
    int cap, flow;
}e[maxm];

void add(int u, int v, int w, int id)
{
    e[no].from = u, e[no].to = v, e[no].nxt = head[u];
    e[no].cap = w, e[no].flow = 0, e[no].id = id;
    head[u] = no++;
    e[no].from = v, e[no].to = u, e[no].nxt = head[v];
    e[no].cap = 0, e[no].flow = 0, e[no].id = id;
    head[v] = no++;
}

void bfs(int s, int t)
{
    int fro = 0, rea = 0;
    memset(level, -1, sizeof(level));
    memset(gap, 0, sizeof(gap));
    gap[0] = 1;
    level[t] = 0;
    q[rea++] = t;
    while(fro != rea)
    {
        int u = q[fro++];
        for(int i = head[u];i != -1;i = e[i].nxt)
        {
            int v = e[i].to;
            if(level[v] == -1)
            {
                level[v] = level[u] + 1;
                gap[level[v]]++;
                q[rea++] = v;
            }
        }
    }
}

int sap(int s, int t, int N)
{
    bfs(s, t);
    memcpy(cur, head, sizeof(head));
    int top = 0, u = s, ans = 0;
    while(level[s] < N)
    {
        if(u == t)
        {
            int minn = INF; int id;
            for(int i = 0;i < top;i++)
            {
                if(minn > e[sta[i]].cap - e[sta[i]].flow)
                {
                    minn = e[sta[i]].cap - e[sta[i]].flow;
                    id = i;
                }
            }
            for(int i = 0;i < top;i++)
            {
                e[sta[i]].flow += minn;
                e[sta[i]^1].flow -= minn;
            }
            ans += minn, top = id;
            u = e[sta[top]^1].to;
            continue;
        }
        bool flag = 0; int v;
        for(int i = cur[u];i != -1;i = e[i].nxt)
        {
            v = e[i].to;
            if(e[i].cap - e[i].flow && level[v] + 1 == level[u])
            {
                flag = 1;
                cur[u] = i;
                break;
            }
        }
        if(flag)
        {
            sta[top++] = cur[u];
            u = v;
            continue;
        }
        int minn = N;
        for(int i = head[u];i != -1;i = e[i].nxt)
        {
            if(e[i].cap - e[i].flow && minn > level[e[i].to])
            {
                minn = level[e[i].to];
                cur[u] = i;
            }
        }
        gap[level[u]]--;
        if(!gap[level[u]]) return ans;
        level[u] = minn + 1;
        gap[level[u]]++;
        if(u != s) u = e[sta[--top]^1].to;
    }
    return ans;
}

void dfs(int u, int op)
{
    vis[u][op] = 1;
    for(int i = head[u];i != -1;i = e[i].nxt)
    {
        int v = e[i].to;
        if(op == 0)
        {
            if(e[i].cap - e[i].flow && !vis[v][op])
                dfs(v, op);
        }
        else
        {
            if(e[i^1].cap - e[i^1].flow && !vis[v][op])
                dfs(v, op);
        }
    }
}

int main()
{
    while(scanf("%d%d%d", &n, &m, &k))
    {
        if(n == 0 && m == 0 && k == 0) break;
        int s = n + m + 1, t = 0;
        no = 0;
        memset(head, -1, sizeof(head));
        for(int i = 1;i <= n;i++) add(s, i, INF, -1);
        for(int i = 1;i <= k;i++)
        {
            scanf("%d%d%d", &a, &b, &x);
            add(a, b, x, i);
        }
        int res = sap(s, t, n + m + 2);
        memset(vis, 0, sizeof(vis));
        dfs(s, 0);
        dfs(t, 1);
        ans.clear();
        for(int i = 0;i < no;i += 2)
        {
            int u = e[i].from, v = e[i].to;
            if(e[i].cap - e[i].flow == 0 && vis[u][0] && vis[v][1])
                ans.push_back(e[i].id);
        }
        for(int i = 0;i < ans.size();i++)
        {
            if(i > 0) printf(" ");
            printf("%d", ans[i]);
        }
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/NPU_SXY/article/details/83098236
ZOJ