{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;

}

 

你可能感兴趣的:(poj)