bzoj 2150 最小路径覆盖

时间:2023-11-14 10:30:26

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

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

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

证明的大概思路是:

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

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

 /**************************************************************
Problem: 2150
User: idy002
Language: C++
Result: Accepted
Time:52 ms
Memory:1652 kb
****************************************************************/ #include <cstdio>
#include <cstring>
#include <vector>
#define N 55
#define S N*N*2
#define oo 0x3f3f3f3f
using namespace std; struct Edge {
int u, v, f;
Edge( int u, int v, int f ):u(u),v(v),f(f){}
}; int n, m, r, c, cnt;
char board[N][N];
int idx[][N][N], src, dst, idc;
int dx[], dy[]; vector<Edge> edge;
vector<int> g[S];
int dep[S], cur[S], qu[S], bg, ed; void makeid() {
idc = ;
src = ++idc;
for( int i=; i<=n; i++ )
for( int j=; j<=m; j++ )
for( int c=; c<; c++ )
idx[c][i][j] = ++idc;
dst = ++idc;
}
void adde( int u, int v, int f ) {
g[u].push_back( edge.size() );
edge.push_back( Edge(u,v,f) );
g[v].push_back( edge.size() );
edge.push_back( Edge(v,u,) );
}
void build() {
for( int i=; i<=n; i++ )
for( int j=; j<=m; j++ ) {
if( board[i][j]!='.' ) continue;
adde( src, idx[][i][j], );
adde( idx[][i][j], dst, );
}
for( int i=; i<=n; i++ )
for( int j=; j<=m; j++ ) {
if( board[i][j]!='.' ) continue;
int u = idx[][i][j];
for( int d=; d<; d++ ) {
int ni = i+dx[d];
int nj = j+dy[d];
if( <=ni&&ni<=n && <=nj&&nj<=m && board[i][j]=='.' ) {
int v = idx[][ni][nj];
adde( u, v, );
}
}
}
}
bool bfs() {
memset( dep, , sizeof(dep) );
qu[bg=ed=] = src;
dep[src] = ;
while( bg<=ed ) {
int u=qu[bg++];
for( int t=; t<g[u].size(); t++ ) {
Edge &e = edge[g[u][t]];
if( e.f && !dep[e.v] ) {
dep[e.v] = dep[e.u]+;
qu[++ed] = e.v;
}
}
}
return dep[dst];
}
int dfs( int u, int a ) {
if( u==dst || a== ) return a;
int remain=a, past=, na;
for( int &t=cur[u]; t<g[u].size(); t++ ) {
Edge &e=edge[g[u][t]];
Edge &ve=edge[g[u][t]^];
if( e.f && dep[e.v]==dep[e.u]+ && (na=dfs(e.v,min(remain,e.f))) ) {
remain -= na;
past += na;
e.f -= na;
ve.f += na;
if( !remain ) break;
}
}
return past;
}
int maxflow() {
int flow = ;
while( bfs() ) {
memset( cur, , sizeof(cur) );
flow += dfs(src,oo);
}
return flow;
}
int main() {
scanf( "%d%d%d%d", &n, &m, &r, &c );
dx[]=r, dy[]=c, dx[]=r, dy[]=-c;
dx[]=c, dy[]=r, dx[]=c, dy[]=-r;
for( int i=; i<=n; i++ ) {
scanf( "%s", board[i]+ );
for( int j=; board[i][j]; j++ )
if( board[i][j]=='.' ) cnt++;
}
makeid();
build();
printf( "%d\n", cnt-maxflow() );
}