bzoj 2150 最小路径覆盖
最小路径覆盖问题是:给定一个DAG,该DAG的一个路径覆盖是一个路径的集合,使得每个点属于且仅属于其中一条路径,问题就是求一个大小最小的路径集合。
做法是将每个点A拆成两个点A1,A2,如果A->B,那么连A1->B2求一个最大匹配。
一个结论是:最小路径数 = 点数 - 最大匹配
证明的大概思路是:
一个路径覆盖与一个边独立集(即一个匹配)一一对应。
一个路径覆盖的路径数 = 点数 - 匹配数 ( 因为 路径数+每条路径的边数和-1 = n个点的无向联通无环图的边数 , 匹配数等于每条路径的边数和 )
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /************************************************************** 2 Problem: 2150 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:52 ms 7 Memory:1652 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #include <vector> 13 #define N 55 14 #define S N*N*2 15 #define oo 0x3f3f3f3f 16 using namespace std; 17 18 struct Edge { 19 int u, v, f; 20 Edge( int u, int v, int f ):u(u),v(v),f(f){} 21 }; 22 23 int n, m, r, c, cnt; 24 char board[N][N]; 25 int idx[2][N][N], src, dst, idc; 26 int dx[4], dy[4]; 27 28 vector<Edge> edge; 29 vector<int> g[S]; 30 int dep[S], cur[S], qu[S], bg, ed; 31 32 void makeid() { 33 idc = 0; 34 src = ++idc; 35 for( int i=1; i<=n; i++ ) 36 for( int j=1; j<=m; j++ ) 37 for( int c=0; c<2; c++ ) 38 idx[c][i][j] = ++idc; 39 dst = ++idc; 40 } 41 void adde( int u, int v, int f ) { 42 g[u].push_back( edge.size() ); 43 edge.push_back( Edge(u,v,f) ); 44 g[v].push_back( edge.size() ); 45 edge.push_back( Edge(v,u,0) ); 46 } 47 void build() { 48 for( int i=1; i<=n; i++ ) 49 for( int j=1; j<=m; j++ ) { 50 if( board[i][j]!='.' ) continue; 51 adde( src, idx[0][i][j], 1 ); 52 adde( idx[1][i][j], dst, 1 ); 53 } 54 for( int i=1; i<=n; i++ ) 55 for( int j=1; j<=m; j++ ) { 56 if( board[i][j]!='.' ) continue; 57 int u = idx[0][i][j]; 58 for( int d=0; d<4; d++ ) { 59 int ni = i+dx[d]; 60 int nj = j+dy[d]; 61 if( 1<=ni&&ni<=n && 1<=nj&&nj<=m && board[i][j]=='.' ) { 62 int v = idx[1][ni][nj]; 63 adde( u, v, 1 ); 64 } 65 } 66 } 67 } 68 bool bfs() { 69 memset( dep, 0, sizeof(dep) ); 70 qu[bg=ed=1] = src; 71 dep[src] = 1; 72 while( bg<=ed ) { 73 int u=qu[bg++]; 74 for( int t=0; t<g[u].size(); t++ ) { 75 Edge &e = edge[g[u][t]]; 76 if( e.f && !dep[e.v] ) { 77 dep[e.v] = dep[e.u]+1; 78 qu[++ed] = e.v; 79 } 80 } 81 } 82 return dep[dst]; 83 } 84 int dfs( int u, int a ) { 85 if( u==dst || a==0 ) return a; 86 int remain=a, past=0, na; 87 for( int &t=cur[u]; t<g[u].size(); t++ ) { 88 Edge &e=edge[g[u][t]]; 89 Edge &ve=edge[g[u][t]^1]; 90 if( e.f && dep[e.v]==dep[e.u]+1 && (na=dfs(e.v,min(remain,e.f))) ) { 91 remain -= na; 92 past += na; 93 e.f -= na; 94 ve.f += na; 95 if( !remain ) break; 96 } 97 } 98 return past; 99 } 100 int maxflow() { 101 int flow = 0; 102 while( bfs() ) { 103 memset( cur, 0, sizeof(cur) ); 104 flow += dfs(src,oo); 105 } 106 return flow; 107 } 108 int main() { 109 scanf( "%d%d%d%d", &n, &m, &r, &c ); 110 dx[0]=r, dy[0]=c, dx[1]=r, dy[1]=-c; 111 dx[2]=c, dy[2]=r, dx[3]=c, dy[3]=-r; 112 for( int i=1; i<=n; i++ ) { 113 scanf( "%s", board[i]+1 ); 114 for( int j=1; board[i][j]; j++ ) 115 if( board[i][j]=='.' ) cnt++; 116 } 117 makeid(); 118 build(); 119 printf( "%d\n", cnt-maxflow() ); 120 }