zoukankan      html  css  js  c++  java
  • bzoj 2150 最小路径覆盖

    最小路径覆盖问题是:给定一个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
    ", cnt-maxflow() );
    120 }
    View Code
  • 相关阅读:
    LeetCode(81): 搜索旋转排序数组 II
    2018年6月8日论文阅读
    LeetCode(80):删除排序数组中的重复项 II
    LeetCode(79): 单词搜索
    LeetCode(78):子集
    LeetCode(77):组合
    LeetCode(76): 最小覆盖子串
    LeetCode(75):分类颜色
    LeetCode(74):搜索二维矩阵
    linux 两个查找工具 locate,find
  • 原文地址:https://www.cnblogs.com/idy002/p/4530835.html
Copyright © 2011-2022 走看看