• 「洛谷P1231」教辅的组成 解题报告


    P1231 教辅的组成

    题目背景

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

    题目描述

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

    输入输出格式

    输入格式:

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

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

    接下来M1行每行包含两个正整数x、y,表示第x本书和第y本练习册可能对应。($1 le x le N1,1le yle 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,M2le 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
    ", ans );
    	return 0;
    }
    
  • 相关阅读:
    linux安装pip
    keepalived 安装和配置
    SecureCRT突然卡死的问题
    python url合并与分离
    centos 长久路由表
    linux shell中 if else以及大于、小于、等于逻辑表达式介绍
    mtime,ctime,atime
    linux学习初体验
    Python数据库连接池DBUtils
    Flask 中的蓝图(BluePrint)
  • 原文地址:https://www.cnblogs.com/louhancheng/p/10118942.html
Copyright © 2020-2023  润新知