最大流 Dinic

一个图, 每条边都有一个容量限制,一般有一个起点,一个终点,求达到平衡状态时,最多有多少流量从起点流向终点。 难点在于建图,建好图直接套模板

HDU 3549 Flow Problem

#include <cstdio>
#include <queue>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 100;
const int maxm = 30000 + 5;
const long long INF = 0x3f3f3f;

struct Edge {
    int from, to, cap, flow;
    Edge(){}
    Edge(int from, int to, int cap, int flow) {
        this->from = from;
        this->to = to;
        this->cap = cap;
        this->flow = flow;
    }
};

struct Dinic {
    int n, m, s, t;
    Edge edges[maxm];
    int head[maxn];
    int nxt[maxm];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];

    void init(int n) {
        this -> n = n;
        memset(head, -1, sizeof(head));
        m = 0;
    }

    void AddEdge(int u, int v, int c) {
        edges[m] = Edge(u, v, c, 0);
        nxt[m] = head[u];
        head[u] = m++;
        edges[m] = Edge(v, u, 0, 0);
        nxt[m] = head[v];
        head[v] = m++;
    }

    bool BFS() {
        memset(vis, 0, sizeof(vis));
        queue<int>Q;
        Q.push(s);
        d[s] = 0;
        vis[s] = 1;
        while (!Q.empty()) {
            int x = Q.front(); Q.pop();
            for (int i = head[x]; i != -1; i = nxt[i]) {
                Edge& e = edges[i];
                if (!vis[e.to] && e.cap > e.flow) {
                    vis[e.to] = 1;
                    d[e.to] = d[x] + 1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int DFS(int x, int a) {
        if (x == t || a == 0) return a;
        int flow = 0, f;
        for (int& i = cur[x]; i != -1; i = nxt[i]) {
            Edge& e = edges[i];
            if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) {
                e.flow += f;
                edges[i^1].flow -= f;
                flow += f;
                a -= f;
                if (a == 0) break;
            }
        }
        return flow;
    }

    int Maxflow(int s, int t) {
        this -> s = s; this -> t = t;
        int flow = 0;
        while (BFS()) {
            for (int i = 0; i < n; i++)
                cur[i] = head[i];
            flow += DFS(s, INF);
        }
        return flow;
    }
} H;

int main() {
    //freopen("in.txt", "r", stdin);
    int n, m, u, v, c, i, t;
    scanf("%d", &t);
    for (int ii = 1; ii <= t; ii++) {
        scanf("%d%d", &n, &m);
        H.init(n + 1);
        for(i=1; i<=m; ++i) {
            scanf("%d%d%d", &u, &v, &c);
            H.AddEdge(u, v, c);
        }
        printf("Case %d: %d\n", ii, H.Maxflow(1, n));
    }
    return 0;
}

HDU 5352 MZL's City

题意有点难:有N个点的一个无向图,最开始每个点都是不可用的,每两点之间都没有边,然后会有M个操作:

1 x ,   可以把和x直接相连或间接相连的点变成可用的,但最多修复K个
2 x, y  可以在x和y之间连一条无向边
3 p     后面有p对数,每对两个数x, y代表x,y之间的边被损毁了

对于每次1操作,输出要修复的点的数量,使总共修复的点的数量最多,在这基础上输出字典序最小的解

每次1操作的时候都会得到一个图,既然想求总共修复的点的数量最多,那么用贪心的思想,每次1操作的时候都尽量修复最多的点: 然后想了一组样例: 先进性操作2建边:1-3 1-4 1-5 1-6 2-5 2-6 然后1开始修复,限制为3,然后拆除 1-5 1-6,然后2开始修复,限制为3,求最多修复多少个城市

正解应该是1先修复1,3和4,然后2修复2,5和6,这样最多修复了1,2,3,4,5,6这6个城市,但是如果第一次先修复了1,5和6,然后题目把边1-5,1-6断掉了,这样第二次只能修复2号点了,最终修复了1,2,5,6这4个点,这样是不对的,所以难的地方在于题目会删边,如果不删边,在建完这个图的时候跑个最大流就行了,然后考虑字典序的关系让越靠后的询问先跑,这样就能保证字典序最小了。

然后删边的问题怎么解决呢?想想删边带来的影响:删边可能会使原本可达的点变的不可达了,减少了总方案数,所以,直接模拟这个删边过程,最终结果就是进行1操作时,(设此点的编号为s),每次我们都能达到s能到达的所有点组成的连通分量,这个连通分量是在上次1操作之后进行添边减边得到的,那么题意就简化成了官方题解那样:左右两排点,每个左边的点可以匹配一些右边的点,最多匹配K次,求最大匹配次数

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

const int maxn = 1000;
const int maxm = 100000;
const long long INF = 0x3f3f3f;

struct Edge {
    int from, to, cap, flow;
    Edge(){}
    Edge(int from, int to, int cap, int flow) {
        this->from = from;
        this->to = to;
        this->cap = cap;
        this->flow = flow;
    }
};

struct Dinic {
    int n, m, s, t;
    Edge edges[maxm];
    int head[maxn];
    int nxt[maxm];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];

    void init(int n) {
        this -> n = n;
        memset(head, -1, sizeof(head));
        m = 0;
    }

    void AddEdge(int u, int v, int c) {
        edges[m] = Edge(u, v, c, 0);
        nxt[m] = head[u];
        head[u] = m++;
        edges[m] = Edge(v, u, 0, 0);
        nxt[m] = head[v];
        head[v] = m++;
    }

    bool BFS() {
        memset(vis, 0, sizeof(vis));
        queue<int>Q;
        Q.push(s);
        d[s] = 0;
        vis[s] = 1;
        while (!Q.empty()) {
            int x = Q.front(); Q.pop();
            for (int i = head[x]; i != -1; i = nxt[i]) {
                Edge& e = edges[i];
                if (!vis[e.to] && e.cap > e.flow) {
                    vis[e.to] = 1;
                    d[e.to] = d[x] + 1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int DFS(int x, int a) {
        if (x == t || a == 0) return a;
        int flow = 0, f;
        for (int& i = cur[x]; i != -1; i = nxt[i]) {
            Edge& e = edges[i];
            if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) {
                e.flow += f;
                edges[i^1].flow -= f;
                flow += f;
                a -= f;
                if (a == 0) break;
            }
        }
        return flow;
    }

    int Maxflow(int s, int t) {
        this -> s = s; this -> t = t;
        int flow = 0;
        while (BFS()) {
            for (int i = 0; i < n; i++)
            cur[i] = head[i];
            flow += DFS(s, INF);
        }
        return flow;
    }
} H;

int n, m, k, id;
int g[maxn][maxn], vis[maxn][maxn], ans[maxn];
vector<int>G[maxn];

void init() {
    memset(g, 0, sizeof(g));
    memset(vis, 0, sizeof(vis));
    id = 0;
}

void dfs(int id, int u) {
    vis[id][u] = 1;
    G[id].push_back(u);
    for (int i = 1; i <= n; i++) {
        if (vis[id][i] || !g[u][i]) continue;
        dfs(id, i);
    }
}

void solve() {
    int s = 0, t = n + id + 1;
    H.init(t + 1);
    for (int i = 1; i <= id; i++) {
        H.AddEdge(s, i, k);
    }
    for (int i = 1; i <= n; i++) {
        H.AddEdge(i + id, t, 1);
    }
    int sum = 0;
    for (int i = id; i >= 1; i--) {
        for (int j = 0; j < (int)G[i].size(); j++) {
            int v = G[i][j];
            H.AddEdge(i, v + id, 1);
        }
        sum += H.Maxflow(s, t);
    }

    for (int i = H.head[s]; i != -1; i = H.nxt[i]) {
        int w = H.edges[i].flow;
        int v = H.edges[i].to;
        ans[v] = w;
    }

    printf("%d\n", sum);
    for (int i = 1; i <= id; i++) {
        printf("%d%c", ans[i], i == id ? '\n' : ' ');
    }
    for (int i = 0; i <= id; i++) G[i].clear();
}

int main() {
    //freopen("in.txt", "r", stdin);
    int tcase;
    scanf("%d", &tcase);
    while (tcase--) {
        scanf("%d%d%d", &n, &m, &k);
        int op, x, y, p;
        init();
        for (int i = 0; i < m; i++) {
            scanf("%d", &op);
            if (op == 1) {
                scanf("%d", &x);
                id++;
                dfs(id, x);
            } else if (op == 2) {
                scanf("%d%d", &x, &y);
                g[x][y] = 1;
                g[y][x] = 1;
            } else if (op == 3) {
                scanf("%d", &p);
                while (p--) {
                    scanf("%d%d", &x, &y);
                    g[x][y] = 0;
                    g[y][x] = 0;
                }
            }
        }
        solve();
    }
    return 0;
}

results matching ""

    No results matching ""