思路:观察宝物周围的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; }