【网络流24题】 7. 试题库问题 题解

题目链接(洛谷 P2763)

题意

假设一个试题库中有\(n\)道试题。每道试题都标明了所属类别。同一道题可能有多个类别属性。现要从题库中抽取\(m\)道题组成试卷。并要求试卷包含指定类型的试题。对于给定的组卷要求,计算满足要求的组卷方案。

思路

本题的思路比较显然,从源点向所有种类连接一条容量为该种类题目数量的边,从每一个种类向该种类的每一道题连一条容量为\(1\)的边,最后从每一道题向汇点连一条容量为\(1\)的边,跑最大流即可。

代码

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

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

using namespace std;
const int maxn = 2000;
const int maxm = 2e5 + 5;
const int S = 0;
const int T = maxn - 1;
const int INF = 0x3f3f3f3f;

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

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

inline void _ADD(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 AddEdge(int from, int to, int val) {
    _ADD(from, to, val);
    _ADD(to, from, 0);
}

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];
}

inline int dfs(int u, int flow) {
    if (u == T || !flow) return flow;
    int res = 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) {
                flow -= di;
                e[i].val -= di;
                e[i ^ 1].val += di;
                res += di;
            }
        }
    }
    if (!res) depth[u] = 0;
    return res;
}

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

int main() {
    memset(head, -1, sizeof(head));
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        int x;
        scanf("%d", &x);
        sum += x;
        AddEdge(S, i, x);
    }
    for (int i = 1; i <= m; i++) {
        int x, y;
        scanf("%d", &x);
        for (int j = 1; j <= x; j++) {
            scanf("%d", &y);
            AddEdge(y, i + n, 1);
        }
        AddEdge(i + n, T, 1);
    }

    // for (int i = 0; i <= n + m; i++) {
    //     printf("%d:\n", i);
    //     for (int j = head[i]; ~j; j = e[j].nxt) {
    //         int to = e[j].to;
    //         if (e[j].val)
    //             printf("%d %d\n", to, e[j].val);
    //     }
    //     // putchar('\n');
    // }


    int res = Dinic();
    if (res < sum) {
        printf("No Solution!\n");
    }
    else {
        for (int i = 1; i <= n; i++) {
            printf("%d:", i);
            for (int j = head[i]; ~j; j = e[j].nxt) {
                int to = e[j].to;
                if (to > n && !e[j].val) {
                    printf(" %d", to - n);
                }
            }
            putchar('\n');
        }
    }
    return 0;
}
posted @ 2020-09-06 20:03  icysky  阅读(157)  评论(0编辑  收藏  举报