zoj1002 FireNet 火力网 C++ 二分图匹配

题目描述

给出一个N*N的网格,用'.'表示空地,用'X'表示墙。在网格上放碉堡,可以控制所在的行和列,但不能穿过墙。

问:最多能放多少个碉堡?


二分图匹配解法:将横向的联通块作为x部,纵向作为y部(如果只有一个格子就被堵死也算一个联通块)。如有相交则连边。每一条边实际对应了一个碉堡,如果有两条边指向同一个点,实际表示两个碉堡放在了同一个联通块,会产生冲突。所以求最大匹配数就对应了最大可能放的碉堡数。


这是我两年前写的辣鸡代码。丑的要死。。

#include<cstdio>
#include<list>
#include<cstring>
using namespace std;
int n, ans;
char map[10][10];
int xsum,ysum;
int x[10][10];
int y[10][10];
int nx[400][3], ny[400][3];
list<int> myl[1000];
bool vis[1000];
int c[1000];
void init()
{
	int i, j, k;
	for (i=1; i<=n; ++i)
		scanf("%s",map[i]+1);
	for (i=1; i<=n; ++i)
		for (j=1; j<=n; ++j)
			if (map[i][j]=='.'){
				++xsum;
				for (k=j; k<=n&&map[i][k]=='.'; ++k) x[i][k]=xsum;
				nx[xsum][0]=i,nx[xsum][1]=j,nx[xsum][2]=k-1;
				j=k;
			}
	for (j=1; j<=n; ++j)
		for (i=1; i<=n; ++i)
			if (map[i][j]=='.'){
				++ysum;
				for (k=i; k<=n&&map[k][j]=='.'; ++k) y[k][j]=ysum;
				ny[ysum][0]=j,ny[ysum][1]=i,ny[ysum][2]=k-1;
				i=k;
			}
}
void BuildGraph()
{
	int i,j;
	for (i=1; i<=xsum; ++i)
		for (j=nx[i][1]; j<=nx[i][2]; ++j)
		{
			int t=nx[i][0];
			if (y[t][j])
			{
				int t1=nx[i][0],t2=nx[i][1];
				myl[x[t1][t2]].push_front(y[t][j]+xsum);
			}
		}
}
bool dfs(int u)
{
	for (list<int>::iterator p=myl[u].begin(); p!=myl[u].end(); p++)
	{
        int v=*p;
	    if (!vis[v])
	    {
	    	vis[v]=1;
			if (!c[v] || dfs(c[v])){
				c[u]=v, c[v]=u;
				return true;
			}
	    }
     }
	return false;
}
void clear()
{
	memset(x,0,sizeof x);
	memset(y,0,sizeof y);
	memset(nx,0,sizeof nx);
	memset(ny,0,sizeof ny);
	memset(map,0,sizeof map);
	memset(c,0,sizeof c);
	for (int i=1;i<900;i++)
		myl[i].clear();
	xsum=ysum=ans=0;
}
int main()
{
	while (1)
	{
		scanf("%d",&n);
		if (n==0) break;
		init();
		BuildGraph();
		for (int i=1; i<=xsum; ++i)
		{
			memset(vis,0,sizeof vis);
			if (!c[i]) ans+=dfs(i);
		}
		printf("%d\n",ans);
		clear();
	}
}


你可能感兴趣的:(zoj1002 FireNet 火力网 C++ 二分图匹配)