Loading

洛谷-P3254 圆桌问题

圆桌问题

最大流

建图完就很简单

考虑将单位和餐桌视为点

  • 限制每个餐桌上的代表所属的单位不同:只要将单位和餐桌之间的流容量设置为 \(1\)

  • 源点对单位有容量为 \(r_i\) 的边,餐桌对汇点有容量为 \(c_i\) 的边

  • 最大流如果为 \(\sum_{i=1}^{m}r_i\) 则说明每个人都能上桌

答案的输出只需要找到所有单位流向餐桌的流是走的哪条边就可以

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 1e5 + 10;
const int inf = 1e9 + 10;
int tp = 1, s, t, len;
int cur[maxn], head[maxn], nex[maxn], to[maxn], val[maxn];
int dep[maxn];

void add(int u, int v, int w)
{
    tp++;
    nex[tp] = head[u];
    val[tp] = w;
    to[tp] = v;
    head[u] = tp;
}

bool bfs()
{
    for(int i=0; i<=len; i++) cur[i] = head[i];
    for(int i=0; i<=len; i++) dep[i] = 0;
    queue<int>q;
    q.push(s);
    dep[s] = 1;
    while(q.size())
    {
        int now = q.front();
        q.pop();
        for(int i=head[now]; i; i=nex[i])
        {
            int u = to[i];
            if(val[i] > 0 && dep[u] == 0)
            {
                dep[u] = dep[now] + 1;
                q.push(u);
            }
        }
    }
    return dep[t];
}

int dfs(int now, int flow)
{
    if(now == t) return flow;
    int ans = 0;
    for(int i=cur[now]; ans < flow && i; i=nex[i])
    {
        cur[now] = i;
        int u = to[i];
        if(val[i] > 0 && dep[u] == dep[now] + 1)
        {
            int x = dfs(u, min(flow - ans, val[i]));
            ans += x;
            val[i] -= x;
            val[i ^ 1] += x;
        }
    }
    return ans;
}

int dinic()
{
    int ans = 0;
    while(bfs())
        ans += dfs(s, inf);
    return ans;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n, m;
    cin >> m >> n;
    s = n + m + 1;
    t = s + 1;
    int sum = 0;
    for(int i=1; i<=m; i++)
    {
        int x;
        cin >> x;
        add(s, i, x);
        add(i, s, 0);
        sum += x;
    }
    for(int i=1; i<=n; i++)
    {
        int x;
        cin >> x;
        add(i + m, t, x);
        add(t, i + m, x);
    }
    for(int i=1; i<=m; i++)
    {
        for(int j=1+m; j<=n+m; j++)
        {
            add(i, j, 1);
            add(j, i, 0);
        }
    }
    len = n + m + 2;
    if(dinic() != sum) cout << 0 << endl;
    else
    {
        cout << 1 << endl;
        for(int i=1; i<=m; i++)
        {
            int temp = 0;
            for(int j=head[i]; j; j=nex[j])
            {
                int u = to[j];
                if(u != s && val[j] == 0)
                {
                    if(temp++) cout << " ";
                    cout << u - m;
                }
            }
            cout << endl;
        }
    }
    return 0;
}

posted @ 2022-06-21 16:03  dgsvygd  阅读(21)  评论(0编辑  收藏  举报