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\n", cnt-maxflow() );
120 }

时间: 2024-11-01 05:38:12

bzoj 2150 最小路径覆盖的相关文章

BZOJ 2150 部落战争(最小路径覆盖)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2150 题意:一个n*m的国家,有些是障碍.对于一支军队,每次只能走C*R的格式(比如马是走1*2的格式),而且只能从上往下走.每个格子只能被一个军队经过.问最少需要多少军队可以遍历完所有格子? 思路:上下能连边的连边.最后就是最小路径覆盖. int a[N][N],n,m; char s[55][55]; int ID(int i,int j) { return (i-1)*m+j;

BZOJ 2150 部落战争 最小路径覆盖 二分图最大匹配

题目大意:给出一张地图,一个军队要征战整个土地.一块土地只能经过一次,有X的地方不能走,军队只会走R*C个格子,只会向下走,问最少需要多少军队能够征战所有的土地. 思路:这个是前几天考试的题,今天居然发现时BZ的原题,还好当时A掉了... 看到每个土地只能经过一次就想到了网络流什么的,再一想想好像是最小路径覆盖啊,然后拆点,建图,Hungary,二分图最小路径覆盖=点数-最大匹配,没了.. CODE: #include <cstdio> #include <cstring> #in

bzoj 2044 三维导弹拦截 —— 最小路径覆盖

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2044 第一问暴力 n^2 即可: 注意这道题对位置没要求!所以先按第一维排序一下即可: 然后拆入点和出点,求一个最小路径覆盖即可. 代码如下: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int const

bzoj 2044 三维导弹拦截——DAG最小路径覆盖(二分图)

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2044 还以为是CDQ.发现自己不会三维以上的-- 第一问可以n^2.然后是求最长不下降子序列吗?dilworth好像不能用吧. 那就是能从自己转移到哪些状态就从自己向哪些状态连边,然后就是最小路径覆盖了.用二分图的 n-最大匹配 . 注意:没有位置的限制所以可以先按 x 排序! #include<iostream> #include<cstdio> #include<c

BZOJ-2150部落战争(最小路径覆盖)

2150: 部落战争 Time Limit: 10 Sec  Memory Limit: 259 MB Description lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国的下部征战来获得更大的领土. A国是一个M*N的矩阵,其中某些地方是城镇,某些地方是高山深涧无人居住.lanzerb把自己的部落分成若干支军队,他们约定: 1. 每支军队可以从任意一个城镇出发,并只能从上往向下征战,不能回头.途中只能经过城镇,不能经过高山深涧. 2. 如果某个城镇被某支军队到过,则

hiho 第118周 网络流四&#183;最小路径覆盖

描述 国庆期间正是旅游和游玩的高峰期. 小Hi和小Ho的学习小组为了研究课题,决定趁此机会派出若干个调查团去沿途查看一下H市内各个景点的游客情况. H市一共有N个旅游景点(编号1..N),由M条单向游览路线连接.在一个景点游览完后,可以顺着游览线路前往下一个景点. 为了避免游客重复游览同一个景点,游览线路保证是没有环路的. 每一个调查团可以从任意一个景点出发,沿着计划好的游览线路依次调查,到达终点后再返回.每个景点只会有一个调查团经过,不会重复调查. 举个例子: 上图中一共派出了3个调查团: 1

hdu3861 强连通+最小路径覆盖

题意:有 n 个点,m 条边的有向图,需要将这些点分成多个块,要求:如果两点之间有路径能够互相到达,那么这两个点必须分在同一块:在同一块内的任意两点相互之间至少要有一条路径到达,即 u 到达 v 或 v 到达 u:每个点都只能存在于单独一个块内.问最少需要划分多少块. 首先,对于如果两点之间能够相互到达则必须在同一块,其实也就是在同一个强连通分量中的点必须在同一块中,所以首先就是强连通缩点.然后在同一块内的任意两点之间要有一条路,那么其实就是对于一块内的强连通分量,至少要有一条路径贯穿所有分量.

COGS728. [网络流24题] 最小路径覆盖问题

算法实现题8-3 最小路径覆盖问题(习题8-13) ´问题描述: 给定有向图G=(V,E).设P是G的一个简单路(顶点不相交)的集合.如果V中每个顶点恰好在P的一条路上,则称P是G的一个路径覆盖.P中路径可以从V的任何一个顶点开始,长度也是任意的,特别地,可以为0.G的最小路径覆盖是G的所含路径条数最少的路径覆盖.设计一个有效算法求一个有向无环图G的最小路径覆盖. 提示: 设V={1,2,...  ,n},构造网络G1=(V1,E1)如下: 每条边的容量均为1.求网络G1的(x0,y0)最大流.

【最小路径覆盖】BZOJ2150-部落战争

[题目大意] 给出一张图,'*'表示不能走的障碍.已知每只军队可以按照r*c的方向行军,且军队与军队之间路径不能交叉.问占据全部'.'最少要多少支军队? [思路] 首先注意题意中有说“军队只能往下走”,弄清楚方向. 从某点往它能走的四个点走一趟,连边.最小路径覆盖=总数-二分图最大匹配. 哦耶!老了,连匈牙利的板子都敲错orzzzzzz 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=55; 4 int m,n