题意:在一个房间里有N种插座和使用M种插座的电器,,这M种插座有些在现有的插座中不包含,不过可以通过适配器来转化,有K种类型的适配器来转化,让你求最少会有多少电器没法使用插座。
思路:最大二分匹配。即求出最多有多少电器有相应的插座,然后用M减去就是所求,不过建图有点难想,我也是看了别人的解题报告才明白的。将电器和相应的插座类型连接起来,将能相互转化的插座连接起来,然后将不能直接使用N种插座而通过适配器的转换就能用的电器和插座连起来,然后就是求M种电器和N种插座的最大匹配了。呃,其实看到很多博客都是用最大流做的,原本这题也是在最大流的练习中找到的,但是我发现最大匹配更好理解,而且二分匹配加上源点和汇点就能转化成最大流。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> #include <map> #include <string> #define N 505 using namespace std ; map<string , int>p ; int mp[N][N] ; int n , m , k , nx ; int f[N] , d[N] ; int dfs( int x ) { int i ; for ( i = m + 1; i <= m + nx ; i++ ) { if ( !f[i] && mp[x][i] ) { f[i] = 1 ; if ( !d[i] || dfs( d[i] )) { d[i] = x ; return 1 ; } } } return 0 ; } //二分匹配模板 int floyd( ) { int i , sum ; sum = 0 ; memset( d , 0 , sizeof ( d )); for ( i = 1 ; i <= m ; i++ ) { memset( f , 0 , sizeof ( f )); if ( dfs( i )) sum++; } return sum ; } int main() { int i , j , t ; string str1 , str2 ; //freopen("input.txt" , "r" , stdin ); //输入N种插座 scanf ( "%d" , &n ) ; p.clear(); nx = n ; for ( i = 1 ; i <= n ; i++ ) { cin>>str1 ; p[str1] = i ; } //输入M种电器 scanf ( "%d" , &m ); for ( i = 1 ; i <= m ; i++ ) { cin>>str1>>str2 ; if ( p[str2] != 0 ) { int x = p[str2] ; mp[i][x+m] = 1 ; } else { n++ ; p[str2] = n ; mp[i][n+m] = 1 ; } } //输入K种转化关系 scanf ( "%d" , &k ); for ( i = 1 ; i <= k ; i++ ) { cin>>str1>>str2 ; if ( p[str1] == 0 ) { n++ ; p[str1] = n ; } if ( p[str2] == 0 ) { n++ ; p[str2] = n ; } mp[p[str1]+m][p[str2]+m] = 1 ; } //将通过适配器可以使用原来N种插座的电器连起来。 for ( i = 1 ; i <= m + n ; i++ ) for ( j = 1 ; j <= m + n ; j++ ) for ( t = 1 ; t <= m + n ; t++ ) if ( mp[j][i] && mp[i][t] && !mp[j][t] ) mp[j][t] = 1 ; int flow = floyd( ); printf ( "%d\n" , m - flow ) ; return 0; }