Peng Lv

毋意,毋必,毋固,毋我。 言必行,行必果。

导航

{POJ}{4000}{National Treasures}{二分匹配}

思路:观察宝物周围的keypoints与宝物位置的距离是奇数,也就转化成为染色问题,将图进行染色,黑色与白色之间构成二分图,求最小边覆盖即可。一道经典的染色转化问题。

#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <memory>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <stack>
using namespace std;

const int MAXN = 2800;
const int INF = (1<<30);

#define CLR(x,y) memset(x,y,sizeof(x))
#define MIN(m,v) (m)<(v)?(m):(v)
#define MAX(m,v) (m)>(v)?(m):(v)
#define ABS(x) ((x)>0?(x):-(x))
#define rep(i,x,y) for(i=x;i<y;++i)

int dir[12][2]={{-1,-2},{-2,-1},{-2,1},{-1,2},
	{1,2},{2,1},{2,-1},{1,-2},
	{-1,0},{0,1},{1,0},{0,-1}};
int r,c,ind,ans;
int g[MAXN][MAXN];
int tt;
typedef struct{
	int v,next;
}Edge;
Edge edge[MAXN*MAXN];
int net[MAXN];
int pre[MAXN];
bool vt[MAXN];

bool _check(const int& x, const int& y )
{
	if( x < 0 || x >= r || y < 0 || y >= c)
		return false;
	return true;
}
void add_edge(const int& u , const int& v)
{
	edge[ind].v = v;
	edge[ind].next = net[u];
	net[u] = ind;
	++ind;
}
bool dfs(const int& u)
{
	int i,v;
	for( i = net[u]; i != -1; i = edge[i].next){
		v = edge[i].v;
		if( !vt[v] ){
			vt[v] = true;
			if( pre[v] == -1 || dfs(pre[v])){
				pre[v] = u;
				return true;
			}
		}
	}
	return false;
}
void init()
{
	CLR(net,-1);
	CLR(pre,-1);
	CLR(vt,0);
	ind = 0;
	return ;
}
void make_graph()
{
	int i,j,tmp,u,v,x,y,k;
	rep(i,0,r)
		rep(j,0,c){
			rep(k,0,13){
				if( g[i][j] == -1 )
					continue;
				if(g[i][j] & (1<<k)){
					x = i + dir[k][0];
					y = j + dir[k][1];
					if( !_check(x,y) )
						continue;
					if( g[x][y] == -1)
						continue;
					u = i*c + j;
					v = x*c + y;
					if( (i+j)&1 )
						add_edge(v,u);
					else
						add_edge(u,v);
				}
			}
		}
	return ;
}
int work()
{
	int i,j,u,v,tmp;
	rep(i,0,r)
		rep(j,0,c)
			scanf("%d",&g[i][j]);
	make_graph();
	int cnt = r*c;
	ans = 0;
	rep(i,0,cnt){
		CLR(vt,0);
		if( dfs(i) )
			++ans;
	}
	printf("%d. %d\n",tt,ans);
	return 0;
}
int main()
{
	tt = 0;
	while(scanf("%d%d",&r,&c)){
		++tt;
		if( r==0 || c == 0)
			break;
		init();
		work();
	}
	return 0;
}

 

posted on 2012-05-19 14:02  Lvpengms  阅读(624)  评论(0编辑  收藏  举报