洛谷P2763题解
吐槽一下:蜜汁UKE是什么玩意?!
题目分析:
观察题面,
对于给定的组卷要求,计算满足要求的组卷方案,可以发现这是一道明显的有条件的二分图匹配问题,于是考虑建模。建一个超级源点,一个超级汇点;源点与试题相连,汇点与类型相连。
重点是类型的题数的建模。可以从感性来理解一下,其实这有一点限流的意思,每个类型只要求有这么多的题量,不能超出,于是考虑在类型与汇点相连的时候将容量设为类型的题数,在算最大流的时候将题量限制住,就能满足题面的要求了。(希望大家能明白我的意思 \(QwQ\) )
最后的图即为:超级源点与试题相连,容量为1;类型与对应的试题相连,容量为1;类型与超级汇点相连,容量为类型的题数。具体来说,超级源点 \(S\) 为节点 \(1\) ,试题为节点 \(2—n+1\),类型为节点 \(n+2—n+k+1\) 超级汇点 \(T\) 为节点 \(n+k+2\) 。
建模完成之后,考虑记录方案。
- 因为 \(Dinic\) 算法是通过 \(Xor\;1\) 来完成正向边与反向边的转变的,故正向边的 \(e[i].to\) 为路径终点,反向边的 \(e[i\;Xor\;1].to\) 为路径起点, 所以可以通过枚举每一条边来找到相应的节点。
- 又因为反向边的 \(e[i\;Xor\;1].v\) 的初始化为0,当 \(e[i\;Xor\;1].v\neq0\) 时,即代表这条边是最大流跑过的边,也相当于这条边被匹配了。
- 最后排除掉超级源点与超级汇点的情况。
如果 \(Dinic\) 跑一遍下来,ans(即最大流)依然为0,则本数据没有答案(即输出"No Solution!")。
code(带详细注释):
#include<bits/stdc++.h>
#define Maxn 4010
#define Maxm 10010
#define int long long
using namespace std;
int k,n;
inline void read(int &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
int S,T;
int ans=0,dep[Maxn];
struct edge
{
int to,next,v;
}e[Maxm<<1];//一定注意要开两倍空间(正反两条边)
int head[Maxn],ei=1;//一定注意这里的ei为奇数
void add(int x,int y,int v)
{
ei++;
e[ei].to=y;
e[ei].v=v;
e[ei].next=head[x];
head[x]=ei;
}
int bfs()
{
queue<int>qu;
memset(dep,0,sizeof(dep));
dep[S]=1;
qu.push(S);
while(!qu.empty())
{
int fr=qu.front();
qu.pop();
for(int i=head[fr];i;i=e[i].next)
{
int to=e[i].to;
if(dep[to]!=0||e[i].v==0) continue;
qu.push(to);
dep[to]=dep[fr]+1;
}
}
return dep[T]!=0;
}
int dfs(int from,int maxflow)
{
if(from==T) return maxflow;
int flow=0;
for(int i=head[from];i;i=e[i].next)
{
int to=e[i].to;
if(dep[to]!=dep[from]+1||e[i].v==0) continue;
int rst=dfs(to,min(maxflow-flow,e[i].v));
if(rst==0) dep[to]=0;
e[i].v-=rst;
e[i^1].v+=rst;
flow+=rst;
if(flow==maxflow) break;
}
return flow;
}
void dinic()
{
while(bfs())
{
ans+=dfs(S,LLONG_MAX);
}
}
signed main()
{
read(k),read(n);
S=1,T=k+n+2;//超级源点与超级汇点
for(int i=1;i<=n;i++)
{
add(S,i+1,1);
add(i+1,S,0);
//超级源点与试题相连,容量为1
}
for(int i=1,x;i<=k;i++)
{
read(x);
add(i+n+1,T,x);
add(T,i+n+1,0);
//类型与超级汇点相连,容量为类型的题数
}
for(int i=1,p;i<=n;i++)
{
read(p);
for(int j=1,x;j<=p;j++)
{
read(x);
add(i+1,x+n+1,1);
add(x+n+1,i+1,0);
//类型与对应的试题相连,容量为1
}
}
dinic();//跑dinic
if(ans==0)//没有答案
{
puts("No Solution!");
return 0;
}
for(int num=1;num<=k;num++)//枚举所有类型
{
printf("%lld:",num);
for(int i=2;i<=ei;i+=2)//枚举每一条边来找到相应的节点
{
if(e[i].to!=S&&e[i].to!=T&&e[i^1].to!=S&&e[i^1].to!=T)//排除掉超级源点与超级汇点的情况
{
if(e[i^1].v!=0)//这条边已经被匹配了
{
if(e[i].to-n-1==num)//判断是否为当前类型
{
printf("%lld ",e[i^1].to-1);
}
}
}
}
printf("\n");
}
return 0;
}
网络流注意事项:
- 网络流关键在于建模,精髓也在建模。像本题一样的二分图匹配问题可采取我使用的建模方式:最大匹配=最大流。
- 前向星的计数器初始化时,一定要为奇数。因为第n条边为正向边,第n+1条边为反向边,要实现 \(e[i]\) 为正向边,\(e[i\;Xor\;1]\) 为反向边,就要保证正向边的i为奇数,即计数器要初始化为奇数。
- 前向星边数一定要开两倍空间,因为正向边一条,反向边一条。
洛谷P2763题解的更多相关文章
- [洛谷P3376题解]网络流(最大流)的实现算法讲解与代码
[洛谷P3376题解]网络流(最大流)的实现算法讲解与代码 更坏的阅读体验 定义 对于给定的一个网络,有向图中每个的边权表示可以通过的最大流量.假设出发点S水流无限大,求水流到终点T后的最大流量. 起 ...
- 洛谷P5759题解
本文摘自本人洛谷博客,原文章地址:https://www.luogu.com.cn/blog/cjtb666anran/solution-p5759 \[这道题重在理解题意 \] 选手编号依次为: \ ...
- 关于三目运算符与if语句的效率与洛谷P2704题解
题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图.在每一格平原地形上最 ...
- 洛谷 P2763 试题库问题(网络流24题之一)
题目描述 «问题描述: 假设一个试题库中有n道试题.每道试题都标明了所属类别.同一道题可能有多个类别属性.现要从题库中抽取m 道题组成试卷.并要求试卷包含指定类型的试题.试设计一个满足要求的组卷算法. ...
- c++并查集配合STL MAP的实现(洛谷P2814题解)
不会并查集的话请将此文与我以前写的并查集一同食用. 原题来自洛谷 原题 文字稿在此: 题目背景 现代的人对于本家族血统越来越感兴趣. 题目描述 给出充足的父子关系,请你编写程序找到某个人的最早的祖先. ...
- 洛谷P2607题解
想要深入学习树形DP,请点击我的博客. 本题的DP模型同 P1352 没有上司的舞会.本题的难点在于如何把基环树DP转化为普通的树上DP. 考虑断边和换根.先找到其中的一个环,在上面随意取两个点, 断 ...
- 【洛谷】题解 P1056 【排座椅】
题目链接 因为题目说输入保证会交头接耳的同学前后相邻或者左右相邻,所以一对同学要分开有且只有一条唯一的通道才能把他们分开. 于是可以吧这条通道累加到一个数组里面.应为题目要求纵列的通道和横列的通道条数 ...
- 【洛谷 P2763】 试题库问题(最大流)
题目链接 6/23 这是网络流23题里我第一个没看题解自己写出来一遍过的.. 这题应该是最简单的模型了吧. 从源点向每个类型连一条流量为这个类型要的题数,再从每个类型向可以属于这个类型的所有试题连一条 ...
- [洛谷P2763]试题库问题
题目大意:有 $k$ 种类型和 $n$ 个题目,每个题目会适应部分类型,第$i$个类型需要$s_i$的题,一道题只能满足一种类型,现要求出满足所有类型的题目的方案 题解:看到匹配,想到网络流,源点向试 ...
随机推荐
- linuxprobe培训第1节课笔记2019年7月5日
报了老刘的RHCE培训,这是老刘上课笔记简略版. 老刘在课上介绍了开源共享精神和大胡子(Richard M. Stallman—GNU创始人).linux发展史(Linus Benedict Torv ...
- idea 提示:ERROR util.Shell: Failed to locate the winutils binary in the hadoop binary path java.io.IOException解决方法
Windows系统中的IDEA链接Linux里面的Hadoop的api时出现的问题 提示:ERROR util.Shell: Failed to locate the winutils binary ...
- 字符串匹配问题(暴力,kmp)
对于字符串的匹配问题,现在自己能够掌握的就只有两种方法, 第一种就是我们常用的暴力匹配法,那什么是暴力匹配法呢? 假设我们现在有一个文本串和一个模式串,我们现在要找出模式串在文本串的哪个位置. 文本串 ...
- python接口自动化(三十二)--Python发送邮件(常见四种邮件内容)番外篇——上(详解)
简介 本篇文章与前边没有多大关联,就是对前边有关发邮件的总结和梳理.在写脚本时,放到后台运行,想知道执行情况,会通过邮件.SMS(短信).飞信.微信等方式通知管理员,用的最多的是邮件.在linux下, ...
- CDQZ集训DAY3 日记
早上起来之后依然开始考试.然而由于校方觉得都挨在一起没有考试氛围,分了两个机房,一开始还没人去,听说另一个机房配置好了之后一堆人开始往外冲,由于我天真的数了一下我是不是要走的,晚了一步,于是乎被教练员 ...
- MyBatis bind标签的用法
From<MyBatis从入门到精通> <!-- 4.5 bind用法 bind标签可以使用OGNL表达式创建一个变量并将其绑定到上下文中. 需求: concat函数连接字符串,在M ...
- 从动态代理到Spring AOP(上)
一.前言 虽然平时日常开发很少用到动态代理,但是动态代理在底层框架等有着非常重要的意义.比如Spring AOP使用cglib和JDK动态代理,Hibernate底层使用了javassit和cglib ...
- 批量替换git目录的远程仓库URL地址脚本
需求: 1. 输入work-dir 工作目录 2. 扫描工作目录中的子目录 3. 对每一个子目录, 判断是否是git repo 4. 确认是git repo, 获取git origin remote- ...
- UVA101 The Blocks Problem 题解
题目链接:https://www.luogu.org/problemnew/show/UVA101 这题码量稍有点大... 分析: 这道题模拟即可.因为考虑到所有的操作vector可最快捷的实现,所以 ...
- Python学习1——Python中的 split() 函数
函数:split() Python中有split()和os.path.split()两个函数,此处简单介绍split()函数:split():拆分字符串.通过指定分隔符对字符串进行切片,并返回分割后的 ...