UVa 11248 Frequency Hopping(最小割入门)

本文介绍了一种改进的最大流算法——ISAP算法,并通过一个具体的有向网络问题进行讲解。该算法能够有效地解决最大流问题,并提供了求解最小割的方法。通过对ISAP算法的详细解析,包括数据结构的设计、关键步骤的实现,以及算法优化技巧等内容,帮助读者深入理解这一高效算法。
摘要由CSDN通过智能技术生成

题意:

给定一个有向网络,每条边均有一个容量。问是否存在一个点 1 到点 N 流量为 C 的流。如果不存在,是否可以恰好修改一条弧的容量,使得存在这样的流。

思路:

1. 首先求最大流,若最大流大于 C ,则直接输出即可。如果不大于 C 则需要修改最小割里面的弧;

2. 关于如何求最小割:求出最大流之后,S->T 已经不存在一条增广路径了。但是仍然按照增广路径的走法,遍历出分别包含 S T 的点集;

3. 关于上面可以反向来理解:如果点集 T 中有一个点位于点集 S,则增加这两点之间的流量就能继续找到一条增广路径,这显然是违背最大流的;

4. 修改割里面的弧,每次求出相应的最大流即可。中间用到 2 点优化,一是在以前的最大流基础上增广,二是每次求最大流只需要求是否满足需求即可;

 

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

const int MAXN = 110;
const int INFS = 0x3FFFFFFF;

struct edge {
    int from, to, cap, flow;
    edge(int _from, int _to, int _cap, int _flow) 
        : from(_from), to(_to), cap(_cap), flow(_flow) {}
    bool operator < (const edge& rhs) const {
        if (from == rhs.from) return to < rhs.to;
        return from < rhs.from;
    }
};

class ISAP {
public:
    void clearall(int n) {
        this->n = n;
        for (int i = 0; i < n; i++)
            G[i].clear();
        edges.clear();
    }
    bool bfs() {
        queue<int> Q;
        d[t] = 0;
        memset(vis, false, sizeof(vis));
        vis[t] = true;
        Q.push(t);
        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] = true;
                    d[e.from] = d[x] + 1;
                    Q.push(e.from);
                }
            }
        }
        return vis[s];
    }

    void addedge(int u, int v, int cap) {
        edges.push_back(edge(u, v, cap, 0));
        edges.push_back(edge(v, u, 0, 0));
        G[u].push_back(edges.size() - 2);
        G[v].push_back(edges.size() - 1);
    }
    int augment() {
        int x = t, a = INFS;
        while (x != s) {
            edge& e = edges[p[x]];
            a = min(a, e.cap - e.flow);
            x = e.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, int need) {
        this->s = s, this->t = t;
        bfs();
        memset(gap, 0, sizeof(gap));
        for (int i = 0; i < n; i++) 
            cur[i] = 0, gap[d[i]] += 1;

        int x = s, flow = 0;
        while (d[s] < n) {
            if (x == t) {
                flow += augment();
                if (flow >= need) return flow;
                x = s;
            }
            bool flag = false;
            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) {
                    flag = true;
                    cur[x] = i;
                    p[e.to] = G[x][i];
                    x = e.to;
                    break;
                }
            }
            if (!flag) {
                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 (--gap[d[x]] == 0) break;
                gap[d[x] = m+1] += 1;
                cur[x] = 0;
                if (x != s) x = edges[p[x]].from;
            }
        }
        return flow;
    }
    void mincut(vector<int>& cut) {
        bfs();
        for (int i = 0; i < edges.size(); i++) {
            edge& e = edges[i];
            if (!vis[e.from] && vis[e.to] && e.cap > 0)
                cut.push_back(i);
        }
    }
    void reduce() {
        for (int i = 0; i < edges.size(); i++)
            edges[i].cap -= edges[i].flow;
    }
    void clearflow() {
        for (int i = 0; i < edges.size(); i++)
            edges[i].flow = 0;
    }
public:
    int n, s, t;
    vector<edge> edges;
    vector<int> G[MAXN];
    int p[MAXN], d[MAXN], cur[MAXN], gap[MAXN];
    bool vis[MAXN];
};

ISAP sap;

int main() {
    int n, e, c, cases = 0;
    while (scanf("%d%d%d", &n, &e, &c) && n) {
        sap.clearall(n);
        while (e--) {
            int u, v, fp;
            scanf("%d%d%d", &u, &v, &fp);
            sap.addedge(u - 1, v - 1, fp);
        }
        int flow = sap.maxflow(0, n - 1, INFS);
        printf("Case %d: ", ++cases);
        if (flow >= c) {
            printf("possible\n");
        } else {
            vector<int> cut;
            vector<edge> ans;
            sap.mincut(cut);
            sap.reduce();
            for (int i = 0; i < cut.size(); i++) {
                edge& e = sap.edges[cut[i]];
                sap.clearflow();
                e.cap = c;
                if (flow + sap.maxflow(0, n - 1, c - flow) >= c)
                    ans.push_back(e);
                e.cap = 0;
            }
            if(ans.empty()) 
                printf("not possible\n");
            else {
                sort(ans.begin(), ans.end());
                printf("possible option:(%d,%d)", ans[0].from + 1, ans[0].to + 1);
                for(int i = 1; i < ans.size(); i++)
                    printf(",(%d,%d)", ans[i].from + 1, ans[i].to + 1);
                printf("\n");
            }
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/kedebug/archive/2013/04/12/3016801.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值