题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2150
赤裸裸的一道最小路径覆盖,直接上匈牙利或网络流即可。
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <bitset>
using namespace std ;
#define maxv maxn * maxn
#define maxn 51
#define check( x , y ) ( x > 0 && y > 0 && x <= n && y <= m && s[ x ][ y ] == '.' )
struct Match {
struct edge {
int t ;
edge *next ;
} *head[ maxv ] ;
int match[ maxv ] ;
bitset < maxv > used ;
Match( ) {
memset( head , 0 , sizeof( head ) ) ;
memset( match , 0 , sizeof( match ) ) ;
}
void AddEdge( int s , int t ) {
edge *p = new( edge ) ;
p -> t = t , p -> next = head[ s ] ;
head[ s ] = p ;
}
bool dfs( int v ) {
for ( edge *p = head[ v ] ; p ; p = p -> next ) if ( ! used[ p -> t ] ) {
used[ p -> t ] = true ;
if ( ! match[ p -> t ] || dfs( match[ p -> t ] ) ) {
match[ p -> t ] = v ;
return true ;
}
}
return false ;
}
int max_match( int v ) {
int cnt = 0 ;
for ( int i = 0 ; i ++ < v ; ) {
used.reset( ) ;
if ( dfs( i ) ) ++ cnt ;
}
return cnt ;
}
} mat ;
int node[ maxn ][ maxn ] , n , m , V = 0 , r , c ;
char s[ maxn ][ maxn ] ;
int main( ) {
scanf( "%d%d%d%d" , &n , &m , &r , &c ) ;
for ( int i = 0 ; i ++ < n ; ) {
scanf( "%s" , s[ i ] + 1 ) ;
for ( int j = 0 ; j ++ < m ; ) if ( s[ i ][ j ] == '.' ) {
node[ i ][ j ] = ++ V ;
}
}
for ( int i = 0 ; i ++ < n ; ) for ( int j = 0 ; j ++ < m ; ) if ( s[ i ][ j ] == '.' ) {
int x = i + r , y = j + c ;
if ( check( x , y ) ) mat.AddEdge( node[ i ][ j ] , node[ x ][ y ] ) ;
x = i + r , y = j - c ;
if ( check( x , y ) ) mat.AddEdge( node[ i ][ j ] , node[ x ][ y ] ) ;
x = i + c , y = j + r ;
if ( check( x , y ) ) mat.AddEdge( node[ i ][ j ] , node[ x ][ y ] ) ;
x = i + c , y = j - r ;
if ( check( x , y ) ) mat.AddEdge( node[ i ][ j ] , node[ x ][ y ] ) ;
}
printf( "%d\n" , V - mat.max_match( V ) ) ;
return 0 ;
}