码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 2150 最小路径覆盖

时间:2015-05-26 18:31:05      阅读:133      评论:0      收藏:0      [点我收藏+]

标签:

 

最小路径覆盖问题是:给定一个DAG,该DAG的一个路径覆盖是一个路径的集合,使得每个点属于且仅属于其中一条路径,问题就是求一个大小最小的路径集合。

做法是将每个点A拆成两个点A1,A2,如果A->B,那么连A1->B2求一个最大匹配。

一个结论是:最小路径数 = 点数 - 最大匹配

证明的大概思路是:

  一个路径覆盖与一个边独立集(即一个匹配)一一对应。

  一个路径覆盖的路径数 = 点数 - 匹配数 ( 因为 路径数+每条路径的边数和-1 = n个点的无向联通无环图的边数 , 匹配数等于每条路径的边数和 )

 

技术分享
  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 }
View Code

 

bzoj 2150 最小路径覆盖

标签:

原文地址:http://www.cnblogs.com/idy002/p/4530835.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!