{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;
}
浙公网安备 33010602011771号