P1231 教辅的组成

题目背景

滚粗了的HansBug在收拾旧语文书,然而他发现了什么奇妙的东西。

题目描述

蒟蒻HansBug在一本语文书里面发现了一本答案,然而他却明明记得这书应该还包含一份练习题。然而出现在他眼前的书多得数不胜数,其中有书,有答案,有练习册。已知一个完整的书册均应该包含且仅包含一本书、一本练习册和一份答案,然而现在全都乱做了一团。许多书上面的字迹都已经模糊了,然而HansBug还是可以大致判断这是一本书还是练习册或答案,并且能够大致知道一本书和答案以及一本书和练习册的对应关系(即仅仅知道某书和某答案、某书和某练习册有可能相对应,除此以外的均不可能对应)。既然如此,HansBug想知道在这样的情况下,最多可能同时组合成多少个完整的书册。

输入输出格式

输入格式:

第一行包含三个正整数N1、N2、N3,分别表示书的个数、练习册的个数和答案的个数。

第二行包含一个正整数M1,表示书和练习册可能的对应关系个数。

接下来M1行每行包含两个正整数x、y,表示第x本书和第y本练习册可能对应。($1 \le x \le N1,1\le y\le N2 $)

第M1+3行包含一个正整数M2,表述书和答案可能的对应关系个数。

接下来M2行每行包含两个正整数x、y,表示第x本书和第y本答案可能对应。(\(1 \le x \le N1,1 \le y \le N3\))

输出格式:

输出包含一个正整数,表示最多可能组成完整书册的数目。

输入输出样例

输入样例#1:

5 3 4
5
4 3
2 2
5 2
5 1
5 3
5
1 3
3 1
2 2
3 3
4 3

输出样例#1:

2

说明

样例说明:

如题,N1=5,N2=3,N3=4,表示书有5本、练习册有3本、答案有4本。

M1=5,表示书和练习册共有5个可能的对应关系,分别为:书4和练习册3、书2和练习册2、书5和练习册2、书5和练习册1以及书5和练习册3。

M2=5,表示数和答案共有5个可能的对应关系,分别为:书1和答案3、书3和答案1、书2和答案2、书3和答案3以及书4和答案3。

所以,以上情况的话最多可以同时配成两个书册,分别为:书2+练习册2+答案2、书4+练习册3+答案3。

数据规模:

对于数据点1, 2, 3,\(M1,M2\le 20\)

对于数据点4~10,\(M1,M2 \le 20000\)


算法

网络最大流。这里不详细讲,请大家先掌握。

思路

注意,以下出现的所有边边权皆为1,且其反向边边权为0

我们以书、练习册、答案为点建图。

像这样:

S(=0)表示额外建的一个起始点,Ri(=i+N1+N1)表示第i本练习册,Di(=i+N1+N1+N2)表示第i本答案,由于书只有一本,而网络流处理只经过一个点不方便,我们采用一种神奇方法——拆点!也就是说,把一本书看做两个点,要匹配这本书必须经过这本书两点之间的边,这样就可以控制这本书只匹配一次。如图,Pi(=i)、Pi'(=i+N1)表示第i本书。

然后建边。如图,将S与所有Ri相连,将所有的Di与T相连,S作为源点,T作为汇点。如果Pi能匹配Rj,就将Pi与Rj相连。如果Pi能匹配Dj,就将Dj与Pi'之间相连。当然,Pi与Pi'之间也要连一条边。

然后就可以套网络最大流辣。最后得出的答案即为最多的数目。

代码

#include<bits/stdc++.h>
using namespace std;
#define open(s) freopen( s".in", "r", stdin ), freopen( s".out", "w", stdout )
#define MAXN 40005
#define MAXM 150000 int N1, N2, N3;
int M1, M2;
int hd[MAXN], nxt[MAXM << 1], to[MAXM << 1], val[MAXM << 1], tot(1);
int ans, dis[MAXN];
queue<int> Q;
bool vis[MAXN]; int x, y;
int S, T; void Add( int x, int y, int z ){ nxt[++tot] = hd[x]; hd[x] = tot; to[tot] = y; val[tot] = z; } bool BFS(){
while( !Q.empty() ) Q.pop();
memset( dis, 0, sizeof dis );
Q.push(S); dis[S] = 1;
while( !Q.empty() ){
x = Q.front(); Q.pop();
for ( int i = hd[x]; i; i = nxt[i] )
if ( val[i] && !dis[to[i]] ){
dis[to[i]] = dis[x] + 1;
Q.push( to[i] );
if ( to[i] == T ) return 1;
}
}
return 0;
} int DFS( int x, int fl ){
if ( x == T ) return fl;
int res(fl), k;
for ( int i = hd[x]; i && res; i = nxt[i] ){
if ( val[i] && dis[to[i]] == dis[x] + 1 ){
k = DFS( to[i], min( res, val[i] ) );
if ( !k ) dis[to[i]] = 0;
val[i] -= k; val[i^1] += k; res -= k;
}
}
return fl - res;
} int main(){
scanf( "%d%d%d", &N1, &N2, &N3 );
scanf( "%d", &M1 );
for ( int i = 1; i <= M1; ++i ){
scanf( "%d%d", &x, &y ); Add( y + N1, x, 1 ); Add( x, y + N1, 0 );
}
scanf( "%d", &M2 );
for ( int i = 1; i <= M2; ++i ){
scanf( "%d%d", &x, &y ); Add( x + N1 + N2 + N3, y + N1 + N2, 1 ); Add( y + N1 + N2, x + N1 + N2 + N3, 0 );
}
S = 0; T = 1 + N1 + N1 + N2 + N3;
for ( int i = 1; i <= N2; ++i ) Add( S, i + N1, 1 ), Add( i + N1, S, 0 );
for ( int i = 1; i <= N3; ++i ) Add( i + N1 + N2, T, 1 ), Add( T, i + N1 + N2, 0 );
for ( int i = 1; i <= N1; ++i ) Add( i, i + N1 + N2 + N3, 1 ), Add( i + N1 + N2 + N3, i, 0 ); int t;
while( BFS() )
while( ( t = DFS( S, 0x7f7f7f7f ) ) > 0 ) ans += t;
printf( "%d\n", ans );
return 0;
}

「洛谷P1231」教辅的组成 解题报告的更多相关文章

  1. 「洛谷P2891」[USACO07OPEN]吃饭Dining 解题报告

    P2891 [USACO07OPEN]吃饭Dining 题目描述 Cows are such finicky eaters. Each cow has a preference for certain ...

  2. 「区间DP」「洛谷P1043」数字游戏

    「洛谷P1043」数字游戏 日后再写 代码 /*#!/bin/sh dir=$GEDIT_CURRENT_DOCUMENT_DIR name=$GEDIT_CURRENT_DOCUMENT_NAME ...

  3. 「洛谷4197」「BZOJ3545」peak【线段树合并】

    题目链接 [洛谷] [BZOJ]没有权限号嘤嘤嘤.题号:3545 题解 窝不会克鲁斯卡尔重构树怎么办??? 可以离线乱搞. 我们将所有的操作全都存下来. 为了解决小于等于\(x\)的操作,那么我们按照 ...

  4. 「洛谷3338」「ZJOI2014」力【FFT】

    题目链接 [BZOJ] [洛谷] 题解 首先我们需要对这个式子进行化简,否则对着这么大一坨东西只能暴力... \[F_i=\sum_{j<i} \frac{q_iq_j}{(i-j)^2}-\s ...

  5. 「BZOJ2733」「洛谷3224」「HNOI2012」永无乡【线段树合并】

    题目链接 [洛谷] 题解 很明显是要用线段树合并的. 对于当前的每一个连通块都建立一个权值线段树. 权值线段树处理操作中的\(k\)大的问题. 如果需要合并,那么就线段树暴力合并,时间复杂度是\(nl ...

  6. 「洛谷3870」「TJOI2009」开关【线段树】

    题目链接 [洛谷] 题解 来做一下水题来掩饰ZJOI2019考炸的心情QwQ. 很明显可以线段树. 维护两个值,\(Lazy\)懒标记表示当前区间是否需要翻转,\(s\)表示区间还有多少灯是亮着的. ...

  7. 「洛谷5300」「GXOI/GZOI2019」与或和【单调栈+二进制转化】

    题目链接 [洛谷传送门] 题解 按位处理. 把每一位对应的图都处理出来 然后单调栈处理一下就好了. \(and\)操作处理全\(1\). \(or\)操作处理全\(0\). 代码 #include & ...

  8. 「洛谷3469」「POI2008」BLO-Blockade【Tarjan求割点】

    题目链接 [洛谷传送门] 题解 很显然,当这个点不是割点的时候,答案是\(2*(n-1)\) 如果这个点是割点,那么答案就是两两被分开的联通分量之间求组合数. 代码 #include <bits ...

  9. 「洛谷1884」「USACO12FEB」过度种植【离散化扫描线】

    题目链接 [洛谷传送门] 题解 矩阵面积的并模板.(请求洛谷加为模板题) 很明显是要离散化的. 我们将矩阵与\(x\)轴平行的两个线段取出来.并且将这两个端点的\(x1\)和\(x2\)进行离散化. ...

随机推荐

  1. Transformer的PyTorch实现

    Google 2017年的论文 Attention is all you need 阐释了什么叫做大道至简!该论文提出了Transformer模型,完全基于Attention mechanism,抛弃 ...

  2. RequestMapping中produces属性作用

    注解RequestMapping中produces属性可以设置返回数据的类型以及编码,可以是json或者xml: @RequestMapping(value="/xxx",prod ...

  3. 在SpringBoot中使用JWT

    JWT简介 简介 JSON Web token简称JWT, 是用于对应用程序上的用户进行身份验证的标记.也就是说, 使用 JWTS 的应用程序不再需要保存有关其用户的 cookie 或其他sessio ...

  4. 正则 ?<= 和 ?= 用法 以及零宽断言等概念

    正则 ?<=  和 ?= 用法   参考网址:http://baike.baidu.com/link?url=2zORJF9GOjU8AkmuHDLz9cyl9yiL68PdW3frayzLwW ...

  5. 在SQL中number(16,5)中的16和5 及number( 5,-2)中的5和-2是什么意思?

    在SQL中number(16,5)中的16和5 及number( 5,-2)中的5和-2是什么意思? 2018-06-04 19:23:24 xiaonan_IT 阅读数 3672   版权声明:本文 ...

  6. java StringBuffer 与 StringBuilder

    String是不可变类,一旦String对象被创建,包含在对象中的字符序列是不可变的,直到对象被销毁: StringBuffer 与 StringBuilder对象则是可变的! 举例说明这两个的好处: ...

  7. AWS Credentials 使用

    AWS的文档系统真是烂到家了!!!!! To connect to any of the supported services with the AWS SDK for Java, you must ...

  8. java 基本数据类型的自动拆箱与装箱

    ——>  -128~127之间的特殊性.为什么要这样设计,好处? ——>  享元模式(Flyweight Pattern):享元模式的特点是,复用我们内存中已存在的对象,降低系统创建对象实 ...

  9. 【t056】智力问答(multiset做法)

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 新年联欢会上,G.Sha负责组织智力问答节目.G.Sha建立了一个很大很大的超级题库,并衡量了每道题的 ...

  10. 节点列表和HTML集合

    getElementsByName()和getElementByTagName()返回的都是NodeList集合. 而document.images和document0.forms的属性为HTMLCo ...