雖然二分圖模板已然是十分熟悉,但當初練習的時候也只是搜圖論列表一個個的練習模板。
話不多說,分析一下這題的構圖。
4 4
*.*.
.***
***.
..*.
給定的4*4的圖。
要求我們構造木板。每個點的木板可以有橫向和縱向兩方選擇。題中要求選擇最少的木板使全部的點都被蓋住。
於是乎,構造圖就是構造橫向鋪的木板和縱向的木板,在圖中的當前點選擇木板的話,就是橫向木板和縱向木板之間有邊。
1.構造縱向木板
1.4.
.345
234.
..4.
2構造橫向木板
1.2.
.333
444.
..5.
然後 用橫向木板和縱向木板構造二分圖
對橫向木板和縱向木板執行匹配
直接使用匈牙利演算法即可。
#include<stdio.h>#include<iostream>#include<string.h>#define MAXN 51using namespace std;char map[MAXN][MAXN];int x[MAXN][MAXN];int y[MAXN][MAXN];bool ans[MAXN*30][MAXN*30];bool visited[MAXN*30];int match[MAXN*30];int R,C;bool Match( int pre ,int size ){ int i; for( i=1;i<=size;i++ ) if( ans[pre][i] && !visited[i] ) { visited[i]=true; if( match[i]==-1 || Match( match[i],size ) ) { match[i]=pre; return true; } } return false;}int main(){ while( ~scanf("%d %d",&R,&C ) ) { int i,j; for( i=1;i<=R;i++ ) scanf( "%s",&map[i][0]+1 ); int sign1=1,sign2=1; for( i=1;i<=R;i++ ) for( j=1;j<=C;j++ ) { if( map[i][j]=='*' ) x[i][j]=sign1; if( map[i][j]=='*' && map[i][j+1]!='*' )sign1++; } for( j=1;j<=C;j++ ) for( i=1;i<=R;i++ ) { if( map[i][j]=='*' ) y[i][j]=sign2; if( map[i][j]=='*' && map[i+1][j]!='*' )sign2++; } //printf( "%d %d\n",sign1,sign2 ); for( i=1;i<=R;i++ ) for( j=1;j<=C;j++ ) { if( map[i][j]=='*' ) ans[ x[i][j] ][ y[i][j] ]=true; } int res=0; memset( match,-1,sizeof(match) ); for( i=1;i<=sign1;i++ ) { memset( visited,false,sizeof(visited) ); if( Match(i,sign2) ) res++; } printf( "%d\n",res ); } return 0;}