1. 程式人生 > 實用技巧 >【網路流24題】 5. 圓桌問題 題解

【網路流24題】 5. 圓桌問題 題解

題目連結(洛谷 P3254)

題意

有來自\(m\)個不同單位的代表參加一次國際會議。第\(i\)個單位派出了\(r_i\)個代表。

會議的餐廳共有\(n\)張餐桌,第\(i\)張餐桌可容納\(c_i\)個代表就餐。

為了使代表們充分交流,希望從同一個單位來的代表不在同一個餐桌就餐。請給出一個滿足要求的代表就餐方案。

思路

我們考慮從源點向每個單位連線一條容量為該單位人數的邊,從每個桌子向匯點連線一條容量為該桌子人數的邊,然後每個單位向每個桌子都連線一條容量為\(1\)的邊(因為每張桌子上每個單位最多隻能有一個人),然後跑最大流。如果最大流和總人數相同,則有解,否則無解。

程式碼

PS:Dinic寫的太慢(dfs)會被卡QAQ

/**
 * luogu P3254 https://www.luogu.com.cn/problem/P3254
 * Dinic
 **/

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;
const int maxn = 1000;
const int S = 0;
const int T = maxn - 1;
const int INF = 0x5f5f5f5f;

struct Edge {
    int to, val, nxt;
}e[maxn * maxn];

int numedge, head[maxn], n, m, depth[maxn], ans, sum;

inline void AddEdge(int from, int to, int val) {
    e[numedge].to = to;
    e[numedge].val = val;
    e[numedge].nxt = head[from];
    head[from] = numedge;
    numedge++;
}

inline void init() {
    memset(head, -1, sizeof(head));
}

inline bool bfs() {
    memset(depth, 0, sizeof(depth));
    depth[S] = 1;
    queue<int> q;
    q.push(S);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int i = head[u]; ~i; i = e[i].nxt) {
            int to = e[i].to;
            if (!depth[to] && e[i].val > 0) {
                depth[to] = depth[u] + 1;
                q.push(to);
            }
        }
    }
    return depth[T] != 0;
}

int dfs(int u, int flow) {
    if (u == T || !flow) return flow;
    int sum = 0;
    for (int i = head[u]; ~i; i = e[i].nxt) {
        int to = e[i].to;
        if (depth[to] > depth[u] && e[i].val > 0) {
            int di = dfs(to, min(flow, e[i].val));
            if (di > 0) {
                sum += di;
                flow -= di;
                e[i].val -= di;
                e[i ^ 1].val += di;
                // return di;
            }
        }
    }
    if (!sum) depth[u] = 0;
    return sum;
}

inline int Dinic() {
    int res = 0;
    while (bfs()) {
        int d;
        while ((d = dfs(S, INF)))
            res += d;
    }
    return res;
}

int main() {
    init();
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        int x;
        scanf("%d", &x);
        sum += x;
        AddEdge(S, i, x);
        AddEdge(i, S, 0);
    }
    for (int i = 1; i <= m; i++) {
        int x;
        scanf("%d", &x);
        AddEdge(i + n, T, x);
        AddEdge(T, i + n, 0);
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            AddEdge(i, j + n, 1);
            AddEdge(j + n, i, 0);
        }
    }
    ans = Dinic();
    if (ans == sum) {
        printf("1\n");
        for (int i = 1; i <= n; i++) {
            for (int j = head[i]; ~j; j = e[j].nxt) {
                int to = e[j].to;
                if (to > n && e[j].val == 0) {
                    printf("%d ", to - n);
                }
            }
            putchar('\n');
        }
    }
    else {
        printf("0\n");
    }
    return 0;
}