[lnsyoj2593/luoguP3254] 圆桌问题

题解

有来自 m 个不同单位的代表参加一次国际会议。第 i 个单位派出了 ri 个代表。
会议的餐厅共有 n 张餐桌,第 i 张餐桌可容纳 ci 个代表就餐。
为了使代表们充分交流,希望从同一个单位来的代表不在同一个餐桌就餐。请给出一个满足要求的代表就餐方案。

sol

可将单位视为左侧点,餐桌视为右侧点。
首先建立超级源点 S 与超级汇点 TS 与第 i 个左侧点连接一条容量为 ri 的边,第 i 个右侧点与 T 连接一条容量为 ci 的边,最后在每一对左侧点和右侧点间连一条容量为 1 的边,跑最大流即可。当且仅当最大流 |f|=i=1mri 时,有合法方案。输出方案时枚举每一条左右侧点之间的边即可。

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

const int N = 505, M = 82005, INF = 0x3f3f3f3f;

int h[N], e[M], f[M], ne[M], idx;
int d[N], cur[N];
int r[N], c[N];
int n, rn, cn;
int S, T;

void add(int a, int b, int c){
    e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
    e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx ++ ;
}

void build(){
    memset(h, -1, sizeof h);
    n = rn + cn + 2, S = n - 1, T = n;
    for (int i = 1; i <= rn; i ++ )
        for (int j = 1; j <= cn; j ++ )
            add(i, rn + j, 1);
    
    for (int i = 1; i <= rn; i ++ ) add(S, i, r[i]);
    for (int i = 1; i <= cn; i ++ ) add(rn + i, T, c[i]);
}

bool bfs(){
    memset(d, -1, sizeof d);
    queue<int> q;
    d[S] = 0, cur[S] = h[S], q.push(S);
    while (!q.empty()) {
        int t = q.front(); q.pop();
        for (int i = h[t]; ~i; i = ne[i]){
            int j = e[i];
            if (d[j] == -1 && f[i]) {
                d[j] = d[t] + 1;
                cur[j] = h[j];
                if (j == T) return true;
                q.push(j);
            }
        }
    }
    return false;
}

int find(int u, int limit) {
    if (u == T) return limit;
    int flow = 0;
    for (int i = cur[u]; ~i && flow < limit; i = ne[i]){
        int j = e[i];
        cur[u] = i;
        if (d[j] == d[u] + 1 && f[i]) {
            int t = find(j, min(limit - flow, f[i]));
            if (!t) d[j] = -1;
            f[i] -= t, f[i ^ 1] += t, flow += t;
        }
    }
    return flow;
}

int dinic(){
    int res = 0, flow;
    while (bfs()) while (flow = find(S, INF)) res += flow;
    return res;
}

void print(){
    for (int i = 1; i <= rn; i ++ ) {
        for (int j = 1; j <= cn; j ++ ) {
            // printf("@%d %d\n", e[2 * ((i - 1) * cn + j - 1)], e[2 * ((i - 1) * cn + j - 1) + 1]);
            if (f[2 * ((i - 1) * cn + j) - 1]) printf("%d ", j);
        }
        puts("");
    }
}

int main(){
    scanf("%d%d", &rn, &cn);
    int rsum = 0;
    for (int i = 1; i <= rn; i ++ ) scanf("%d", &r[i]), rsum += r[i];
    for (int i = 1; i <= cn; i ++ ) scanf("%d", &c[i]);

    build();

    int res = dinic();
    if (res < rsum) return puts("0"), 0;
    puts("1");
    print();
}
posted @   是一只小蒟蒻呀  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示