其他分享
首页 > 其他分享> > P1231 教辅的组成 【网络流】【最大流】

P1231 教辅的组成 【网络流】【最大流】

作者:互联网

题目背景

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

题目描述

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

输入格式

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

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

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

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

接下来M2行每行包含两个正整数x、y,表示第x本书和第y本答案可能对应。(1<=x<=N1,1<=y<=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<= 20

对于数据点4~10,M1,M2 <= 20000

 

思路

  紫题?就这?

  一读题就是老拆点最大流了。

  但还是有几个要注意的地方。

  一开始没拆点,直接wa7个点,仔细看了题,每本书只能用一次。

  如果每本书能用无数次求有几种组合方式当然是不用拆的,直接跑ISAP求最大流就可以了。

  其次,这道题卡了优化,一开始懒得上ISAP交了一个没优化的 Dinic T了7个点,炸点+当前弧优化的dinic肯定也是能过的,但肯定没ISAP快。

 

CODE

 

#include<cstdio> #include<iostream> #include<cstring> #include<queue> #include<vector> #include<algorithm>
using namespace std;
const int maxn = 1e6 + 7; const int inf = 0x3f3f3f3f;
template<class T>inline void read(T &res) {     char c;T flag=1;     while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';     while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag; }
struct edge{int from,to,cap,flow;};
struct isap {     int n,s,t,p[maxn],d[maxn],cur[maxn],num[maxn];     bool vis[maxn];     vector<int>g[maxn];     vector<edge>edges;     void init(int n,int s,int t) {         this->n = n;         this->s = s;         this->t = t;         for(int i = 1;i <= n;i++) g[i].clear();         edges.clear();     }     void addegde(int from,int to,int cap) {         edges.push_back((edge){from, to, cap, 0});         edges.push_back((edge){to, from, 0, 0});         int m = edges.size();         g[from].push_back(m-2);         g[to].push_back(m-1);     }
    int augment() {///找增广路         int x = t,a = inf;         while(x!=s) {             a = min(a, edges[p[x]].cap - edges[p[x]].flow);             x = edges[p[x]].from;         }         x=t;         while(x != s) {             edges[p[x]].flow += a;             edges[p[x]^1].flow = -a;             x = edges[p[x]].from;         }         return a;     }     int maxflow() {///更新最大流         int flow = 0;         memset(num, 0, sizeof(num));         memset(cur, 0, sizeof(cur));         for(int i = 1; i <= n; i++) num[d[i]]++;         int x = s;         while(d[s] < n) {///最长的一条链上,最大的下标是nv-1,如果大于等于nv说明已断层             if(x == t) {                 flow += augment();                 x = s;//回退             }             bool ok = 0;             for(int i = cur[x]; i < g[x].size(); i++) {                 edge &e = edges[g[x][i]];                 if(d[x] == d[e.to] + 1 && e.cap > e.flow) {                     p[e.to] = g[x][i];                     cur[x] = i;x = e.to;                     ok = 1;                     break;                 }             }             if(!ok) {                 int m = n-1;                 for(int i = 0; i < g[x].size();i++) {                     edge &e=edges[g[x][i]];                     if(e.cap>e.flow) m=min(m,d[e.to]);                 }                 num[d[x]]--;                 if(!num[d[x]]) break;                 d[x] = m+1;                 num[d[x]]++;                 cur[x] = 0;                 if(x != s) x = edges[p[x]].from;             }         }         return flow;     } }ISAP;
int n, p, q; int s, t;
int main() {     read(n), read(p), read(q);     s = 2*n+q+p+1;     t = s+1;     ISAP.init(2 * n + p + q + 7, s, t);     int m2;     read(m2);     for ( int i = 1; i <= m2; ++i ) {         int u, v;         read(u);         read(v);         ISAP.addegde(v, u + p, 1);     }     read(m2);     for ( int i = 1; i <= m2; ++i ) {         int u, v;         read(u);read(v);         ISAP.addegde(n + p + u, v + p + 2 * n, 1);     }     for ( int i = 1; i <= n; ++i ) {         ISAP.addegde(p + i, n + p + i, 1);     }     for ( int i = 1; i <= q; ++i ) {         ISAP.addegde(s, i, 1);     }     for ( int i = 1; i <= p; ++i ) {         ISAP.addegde(n * 2 + p + i, t, 1);     }     // while(bfs()) {     //     Dinic();     // }     printf("%d\n",ISAP.maxflow());     return 0; }

标签:int,flow,教辅,网络,read,P1231,答案,练习册,ISAP
来源: https://www.cnblogs.com/orangeko/p/12562890.html