poj 2226 二分图 最小点覆盖 , 最大流

题目就是问如何用最小的板覆盖所有的草地。可以横着放,也可以竖着放,允许一个草地放多个点。

建图方法就是 每个横向的草地作为X,纵向连续的草地作为Y.     X连接Y的边表示,  这里有他们的公共点。。

很显然,覆盖所有草地,就是覆盖所有的边 ,二分图中,最小点覆盖 = 最大匹配

= =其实如果存在一条边未被选中的节点覆盖,则必然存在一条对应的增广路径

//tpl
//ipqhjjybj_tpl.h
//header.h
#include <cstdio>
#include <cstdlib>
#include <map>
#include <set>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#include <string>

#define mp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define pLL pair<long long ,long long>
#define rep(i,j,k) for(int i = j; i < k;i++)

using namespace std;

const int INF = 0x3f3f3f3f;

const int N = 500;
int g[N][N];
int cx[N],cy[N];
int mark[N];
int nx,ny;

int dfs(int u)
{
    rep(v,0,ny)
    {
        if(g[u][v]&&!mark[v])//u和v不要搞反了
        {
            mark[v]=1;
            if(cy[v]==-1||dfs(cy[v]))
            {
                cx[u]=v;
                cy[v]=u;
                return 1;
            }
        }
    }
    return 0;
}
int maxmatch()
{
    int res=0;
    memset(cx,-1,sizeof(cx));
    memset(cy,-1,sizeof(cy));
    rep(i,0,nx)
    {
        if(cx[i]==-1)
        {
            memset(mark,0,sizeof(mark));
            res+=dfs(i);
        }
    }
	// rep(i,0,nx){
			// printf("cx[%d] = %d\n",i,cx[i]);
			// printf("cy[%d] = %d\n",i,cy[i]);
		// }
    return res;
}  

int a[N][N],b[N][N];
char s[N][N];
int main(){
	int n,m;
	while(scanf("%d %d",&n,&m)!=EOF){
		memset(g,0,sizeof(g));
		rep(i,0,n) scanf("%s",s[i]);
		int cnt = 0;
		rep(i,0,n)
			rep(j,0,m){
				if(s[i][j]=='*'){
					if(i==0 || s[i-1][j]=='.')
						a[i][j] = cnt++;
					else a[i][j] = a[i-1][j];
				}
			}
		nx = cnt;
		cnt = 0;
		rep(i,0,n)
			rep(j,0,m){
				if(s[i][j] == '*'){
					if(j==0 || s[i][j-1]=='.')
						b[i][j] = cnt++;
					else b[i][j] = b[i][j-1];
					 g[a[i][j]][b[i][j]] = 1;
				}
			}
		ny = cnt;
		// rep(i,0,nx){
			// rep(j,0,ny)
				// printf("g[%d][%d]=%d ",i,j,g[i][j]);
			// printf("\n");
		// }

		printf("%d\n",maxmatch());
	}
	return 0;
}

附上我的 最大流写法。。

//tpl
//ipqhjjybj_tpl.h
//header.h
#include <cstdio>
#include <cstdlib>
#include <map>
#include <set>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#include <string>

#define mp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define pLL pair<long long ,long long>
#define rep(i,j,k) for(int i = j; i < k;i++)

using namespace std;

const int INF = 0x3f3f3f3f;

const int N = 1111;
int tot;
int s,t;
int sum;
struct node{
	int u,v,w,next;
	node(){}
	node(int _u,int _v,int _w,int _next){
		u=_u,v=_v,w=_w,next=_next;
	}
}edge[N*N];
int head[N],cur[N],dis[N];
int pre[N],gap[N],aug[N];
const int oo=0x3f3f3f;
void addEdge(int u,int v,int w){
	edge[tot]=node(u,v,w,head[u]);
	head[u]=tot++;
	edge[tot]=node(v,u,0,head[v]);
	head[v]=tot++;
}

int SAP(int s,int e,int n){
	int max_flow=0,v,u=s;
	int id,mindis;
	aug[s]=oo;
	pre[s]=-1;
	memset(dis,0,sizeof(dis));
	memset(gap,0,sizeof(gap));
	gap[0]=n;

	for(int i=0;i <= n;i++)
		cur[i]=head[i];

	while(dis[s]<n){
		if(u==e){
			max_flow += aug[e];
			for(v=pre[e]; v!=-1; v=pre[v]){
				int ed=cur[v];
				edge[ed].w -= aug[e];
				edge[ed^1].w += aug[e];
				aug[v]-=aug[e];
				if(edge[ed].w==0) u=v;
			}
		}
		bool flag=false;
		for(id=cur[u]; id!=-1;id=edge[id].next){
			v=edge[id].v;
			if(edge[id].w > 0 && dis[u]==dis[v]+1){
				flag=true;
				pre[v]=u;
				cur[u]=id;
				aug[v]=min(aug[u],edge[id].w);
				u=v;
				break;
			}
		}
		if(flag==false){
			if(--gap[dis[u]] == 0) break;
			int mindis=n;
			for(id=head[u]; id!=-1; id=edge[id].next){
				v=edge[id].v;
				if(edge[id].w>0 && dis[v] < mindis){
					mindis = dis[v];
					cur[u]=id;
				}
			}
			dis[u] = mindis + 1;
			gap[dis[u]]++;
			if(u!=s)u=pre[u];
		}
	}
	return max_flow;
}

int a[N][N],b[N][N];
char ss[N][N];
int main(){
	int n,m;
	while(scanf("%d %d",&n,&m)!=EOF){
		tot=sum=s=0;
		int tc=0;
		memset(head,-1,sizeof(head));

		rep(i,0,n) scanf("%s",ss[i]);
		int cnt = 0;
		t = ++cnt;
		rep(i,0,n)
			rep(j,0,m){
				if(ss[i][j]=='*'){
					if(i==0 || ss[i-1][j]=='.')
						a[i][j] = ++cnt , addEdge(s,a[i][j],1);
					else a[i][j] = a[i-1][j];
				}
			}

		rep(i,0,n)
			rep(j,0,m){
				if(ss[i][j] == '*'){

					if(j==0 || ss[i][j-1]=='.')
						b[i][j] = ++cnt ,addEdge(b[i][j],t,1);
					else b[i][j] = b[i][j-1];
					//g[a[i][j]][b[i][j]] = 1;
					addEdge(a[i][j],b[i][j],1);

				}
			}

		printf("%d\n",SAP(s,t,cnt+1));
	}
	return 0;
}

poj 2226 二分图 最小点覆盖 , 最大流

时间: 2024-10-12 23:37:26

poj 2226 二分图 最小点覆盖 , 最大流的相关文章

Asteroids POJ - 3041 二分图最小点覆盖

Asteroids POJ - 3041 Bessie wants to navigate her spaceship through a dangerous asteroid field in the shape of an N x N grid (1 <= N <= 500). The grid contains K asteroids (1 <= K <= 10,000), which are conveniently located at the lattice point

hdu 1151 或 poj 1422 二分图 最小点覆盖集

最小点覆盖集的裸题,只要“拆点建边”然后求出最大匹配,则:最小点覆盖集的大小 = 点数 - 最大匹配 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 121; 7 const int M = 5000; 8 bool visit[N]; 9 int mark[N]; 10 int head[N]; 11 int

poj 2226 Muddy Fields(二分图最小点覆盖)

B - Muddy Fields Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 2226 Description Rain has pummeled the cows' field, a rectangular grid of R rows and C columns (1 <= R <= 50, 1 <= C <

POJ3041 Asteroids【二分图最小点覆盖】

题目链接: http://poj.org/problem?id=3041 题目大意: 有一个N*N的矩阵,有些格子上有障碍物(坐标为(x,y) ),在消除这些障碍物的时候,可以一次性消除 该障碍物同一行所有的障碍物,或是一次性消除该障碍物同一列所有的障碍物.只能选择清理该行或是 清理该列.问:最小进行多少次消除,就可以清理所有的障碍物. 思路: 可以将每一行当做一个点,这样总共有N个点,作为二分图的一边.将每一列当做一个点,这样又有N 个点,作为二分图的另一边.将有障碍物的行点和列点连接起来,每

POJ1325 Machine Schedule【二分图最小点覆盖】

题目链接: http://poj.org/problem?id=1325 题目大意: 有两台机器A和B,机器A有N种不同的模式,编号为0~N-1.机器B有M种不同的模式,编号为0~M-1. 在一开始的时候,机器A和B都处于0模式.现在需要用两台机器来处理K项任务,任务编号为0~K-1.每 一项任务都可以在A或B的指定状态下完成.例如任务1可以在机器A的2模式下完成,也可以在机器B的4 模式下完成.对于第i想任务用(i,x,y)来表示第i项任务可以在机器A的x模式下或机器B的y模式下完成. 为了完

POJ2226 Muddy Fields(二分图最小点覆盖集)

题目给张R×C的地图,地图上*表示泥地..表示草地,问最少要几块宽1长任意木板才能盖住所有泥地,木板可以重合但不能盖住草地. 把所有行和列连续的泥地(可以放一块木板铺满的)看作点且行和列连续泥地分别作为XY部,每一块泥地看作边.这样就构造出了一个二分图. 那么,问题就是在这个二分图中就是选出最少的点覆盖所有的边,即二分图最小点覆盖集,而二分图最小点覆盖集=二分图最大匹配. 1 #include<cstdio> 2 #include<cstring> 3 #include<qu

hihoCoder #1127 : 二分图二&#183;二分图最小点覆盖和最大独立集

#1127 : 二分图二·二分图最小点覆盖和最大独立集 Time Limit:10000ms Case Time Limit:1000ms Memory Limit:256MB 描述 在上次安排完相亲之后又过了挺长时间,大家好像都差不多见过面了.不过相亲这个事不是说那么容易的,所以Nettle的姑姑打算收集一下之前的情况并再安排一次相亲.所以现在摆在Nettle面前的有2个问题: 1.姑姑想要了解之前所有相亲的情况.对于任一个一次相亲,只要跟参与相亲的两人交流就可以得到这次相亲的情况.如果一个人

POJ1325_Machine Schedule(二分图/最小点覆盖=最大匹配)

解题报告 http://blog.csdn.net/juncoder/article/details/38147135 题目传送门 题意: A机器有n个模式,B机器有m个模式,每个作业可以在任何机器的特定模式下工作,转换模式需要耗时,求最小耗时 思路: 把AB两机器的模式当成二分图顶点,模式之间的连线就是某个作业可以在该两个模式下工作,就转换成求最小点覆盖,用最少的点覆盖最多的边. 最小点覆盖=最大匹配 #include <queue> #include <cmath> #incl

HDU2119_Matrix(二分图/最小点覆盖=最大匹配)

解题报告 题目传送门 题意: 题意类似与POJ3041 思路: 见POJ3041解题报告 最小点覆盖. #include <iostream> #include <cstring> #include <cstdio> using namespace std; int mmap[110][110],vis[110],pre[110],n,m; int dfs(int x) { for(int i=1; i<=m; i++) { if(!vis[i]&&