[返回网络流 24 题索引]

题目描述

假设一个试题库中有 nnn 道试题。每道试题都标明了所属类别。同一道题可能有多个类别属性。现要从题库中抽取 mmm 道题组成试卷。并要求试卷包含指定类型的试题。

Solution 2763\text{Solution 2763}Solution 2763

设表示题目的点为 PPP,表示类别的为 KKK。

首先从源 STSTST 到 PiP_iPi​ 连一条流量为 111 的边,即每道题只能选一次;

然后从 KiK_iKi​ 到 EDEDED 连一条流量为 aia_iai​ 的边,即每种类型需要选 aia_iai​ 道;

最后 ∀j∈Ti\forall j \in T_i∀j∈Ti​,从 PiP_iPi​ 给 KjK_jKj​ 连边,即每道题可以以相应类型的名义被选出。

方案即是所有 题目到类型 的连边中满流的那些。如果流量不满则无解。

附上 dalao ⚡cdecl⚡ 的代码。

#include <cstdio>
#include <cstring>
#include <queue> const int N = 1e3 + 31, M = 3e4 + 43, K = 22, INF = 0x3f3f3f3f; struct edge {
int to, next, w;
} e[M << 1];
int head[N], cnt = 1;
void addedge(int x, int y, int z) {
e[++cnt] = (edge){y, head[x], z};
head[x] = cnt;
e[++cnt] = (edge){x, head[y], 0};
head[y] = cnt;
} int level[N];
bool bfs(int s, int t) {
memset(level, 0, sizeof level);
std::queue<int> q;
q.push(s);
level[s] = 1;
while (!q.empty()) {
int pos = q.front();
q.pop();
for (int i = head[pos]; i; i = e[i].next) {
int nx = e[i].to;
if (level[nx] || !e[i].w) continue;
level[nx] = level[pos] + 1;
q.push(nx);
}
}
return level[t];
} int dfs(int s, int t, int flow) {
if (s == t) return flow;
int ret = 0;
for (int i = head[s]; flow && i; i = e[i].next) {
int nx = e[i].to;
if (level[s] + 1 == level[nx] && e[i].w) {
int tmp = dfs(nx, t, std::min(flow, e[i].w));
e[i].w -= tmp;
e[i ^ 1].w += tmp;
ret += tmp;
flow -= tmp;
}
}
return ret;
} int dinic(int s, int t) {
int ret = 0;
while (bfs(s, t)) ret += dfs(s, t, INF);
return ret;
} std::queue<int> out[K];
int n, k, x, y, sum;
int main() {
scanf("%d%d", &k, &n);
for (int i = 1; i <= k; i++) {
scanf("%d", &x);
addedge(n + i + 1, n + k + 2, x);
sum += x;
}
for (int i = 1; i <= n; i++) {
addedge(1, i + 1, 1);
for (scanf("%d", &x); x--;) {
scanf("%d", &y);
addedge(i + 1, n + y + 1, 1);
}
}
if (dinic(1, n + k + 2) != sum) return puts("No Solution!"), 0;
for (int i = 1; i <= n; i++) {
for (int j = head[i + 1]; j; j = e[j].next) {
if ((~j & 1) && !e[j].w) {
out[e[j].to - n - 1].push(i);
break;
}
}
}
for (int i = 1; i <= k; i++) {
printf("%d: ", i);
if (out[i].empty()) puts("");
while (!out[i].empty()) {
printf("%d%c", out[i].front(), " \n"[out[i].size() == 1]);
out[i].pop();
}
}
}

最新文章

  1. express+gulp构建项目(四)env环境变量
  2. c++多态
  3. 技术专题—Python黑客【优质内容聚合贴】
  4. Activity生命周期(二)
  5. 记save函数
  6. Dividing 多重背包 倍增DP
  7. HDU4496_D-City(并查集删边/逆向)
  8. STM32W108无线传感器网络嵌入式uCOS-II的移植及实时环境监測
  9. Vue结合slot插槽分发父组件内容实现高度复用、更加灵活的dialog组件
  10. Struts2处理流程性需求的一种解决方案
  11. Oracle通过Navicat导入表数据与机构,数据无法直接查询,需要加双引号的问题
  12. Charles手机抓包常见问题(各种常见坑)
  13. 大型分布式架构设计与实现-第一章SOA(面向服务的体系架构)
  14. SPHINX 文档写作工具安装简要指南 - windows 版 - 基于python
  15. 第28月第22天 iOS动态库
  16. React Native学习方法论
  17. 8.一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?
  18. 干货分享 9款精挑细选的HTML5应用
  19. mongodb命令(1)
  20. 初学node.js-nodejs安装运行(1)

热门文章

  1. 三句话告诉你break、return、continue!
  2. XPath匹配含有指定文本的标签---contains的用法
  3. cocos meta 文件git显示
  4. NodeManager概述(基本职能和内部架构)
  5. 利用IntelliJ IDEA与Maven开发scala程序,并打包提交到spark集群
  6. Spring入门教程
  7. docker安装centos6
  8. 简述python的turtle绘画命令及解释
  9. 转载:alpha测试和beta测试的区别;黑盒测试和白盒测试的区别;
  10. 从 Int 到 Integer 对象,细细品来还是有不少东西