HDU-1045 Hopcroft-Karp算法

/*
模型转换:
	将每行被墙隔开的连续区域称为‘块’
	把横向块看做二分图的顶点集合X 竖向块看做集合Y
	横向块和竖向块有冲突就在他们之间连边
*/
#include "stdio.h"
#include "string.h"
#include "queue"
using namespace std;
const int inf = 1<<30;
const int maxn = 15;
int n;
int nx,ny;
char maps[maxn][maxn];        //存地图
int xs[maxn][maxn],ys[maxn][maxn];		 // 水平的块 垂直块
bool vis[maxn];
bool map[maxn][maxn];
int cx[maxn],cy[maxn];
int dx[maxn],dy[maxn];
int dis;
//Hopcroft-Karp算法 有点类似dinic 都是先对图BFS分层再沿层数DFS找增广路
//====================================核心
bool searchpath()
{
	queue<int>que;
	dis = inf;
	memset( dx,-1,sizeof(dx) );
	memset( dy,-1,sizeof(dy) );
	for( int i = 1; i <= nx; i ++  )
	{
		if( cx[i] == -1 )
		{
			que.push(i);
			dx[i] = 0;
		}
	}
	while( !que.empty() )
	{
		int u = que.front(); que.pop();
		if( dx[u] > dis )	break;
		for( int v = 1; v <= ny; v ++ )
		{
			if( map[u][v] && dy[v] == -1 )
			{
				dy[v] = dx[u] + 1;
				if( cy[v] == -1 )
					dis = dy[v];
				else
				{
					dx[cy[v]] = dy[v] + 1;
					que.push(cy[v]);
				}
			}
		}
	}
	return dis != inf;
}

int findpath( int u )
{
	for( int v = 1; v <= ny; v++ )
	{
		if( map[u][v] && !vis[v] && dy[v] == dx[u] + 1 )
		{
			vis[v] = 1;
			if( cy[v] != -1 && dy[v] == dis )
				continue;
			if( cy[v] == -1 || findpath( cy[v] ) )
			{
				cy[v] = u;
				cx[u] = v;
				return true;
			}
		}
	}
	return false;
}

int MaxMatch()
{
	int ans = 0;
	int i;
	memset(cx,-1,sizeof(cx));
	memset(cy,-1,sizeof(cy));
	while( searchpath() )
	{		
		memset(vis,0,sizeof(vis));
		for( i = 1; i <= nx; i++ )
		{
			if( cx[i] == -1 )
			{
				ans += findpath(i);
			}
		}
	}
	return ans;
}
//====================================

int main()
{
	while( scanf("%d",&n) != EOF , n )
	{
		for( int i = 1; i <= n; i ++ )
		{
			getchar();
			for( int j = 1; j <= n; j ++ )
			{
				scanf("%c",&maps[i][j]);
			}
		}
		int flag;
		nx = ny = 0;
		for( int i = 1; i <= n; i ++ )
		{
			flag = 0;
			for( int j = 1; j <= n; j ++ )
			{
				if( maps[i][j] == '.' )
				{
					if( !flag )	nx++;
					xs[i][j] = nx;
					flag = 1;
				}
				else
				{
					flag = 0;
				}
			}
		}
		for( int i = 1; i <= n; i ++ )
		{
			flag = 0;
			for( int j = 1; j <= n; j ++ )
			{
				if( maps[j][i] == '.' )
				{
					if( !flag )	ny++;
					ys[j][i] = ny;
					flag = 1;
				}
				else
				{
					flag = 0;
				}
			}
		}
		memset( map,0,sizeof(map) );
		for( int i = 1; i <= n; i ++ )
		{
			for( int j = 1; j <= n; j ++ )
			{
				if( xs[i][j] && ys[i][j] )
					map[ xs[i][j] ][ ys[i][j] ] = 1;
			}
		}
		printf("%d\n",MaxMatch() );
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值