本质上是二分图求最大独立集。
优化:不必建两列点,只用建一列就好了。因为hungary本质上是使用ly[]这个数组,和是不是两列点没有关系。如果建了两列点仿佛过不了这道题。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 205 #define maxv 80050 #define maxe 500500 using namespace std; int n,map[maxn][maxn],g[maxv],nume=1,ans=0,ly[maxv],flag=0,used[maxv],tot=0; int dx[]={0,-2,-1,1,2,2,1,-1,-2},dy[]={0,1,2,2,1,-1,-2,-2,-1}; struct edge { int v,nxt; }e[maxe]; char s[maxn]; void addedge(int u,int v) { e[++nume].v=v; e[nume].nxt=g[u]; g[u]=nume; } int f(int x,int y) {return (x-1)*n+y;} bool judge(int x,int y) { return ((x>=1) && (x<=n) && (y>=1) && (y<=n)); } bool hungary(int x) { for (int i=g[x];i;i=e[i].nxt) { int v=e[i].v; if (used[v]==flag) continue; used[v]=flag; if ((ly[v]==-1) || (hungary(ly[v]))) { ly[v]=x; return true; } } return false; } int main() { scanf("%d",&n); memset(ly,-1,sizeof(ly)); for (int i=1;i<=n;i++) { scanf("%s",s); for (int j=0;j<n;j++) { map[i][j+1]=s[j]-'0'; if (!map[i][j+1]) tot++; } } for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) for (int k=1;k<=4;k++) { int nx=i+dx[k],ny=j+dy[k]; if (judge(nx,ny) && (!map[nx][ny]) && (!map[i][j])) { addedge(f(i,j),f(nx,ny)); addedge(f(nx,ny),f(i,j)); } } for (int i=1;i<=n*n;i++) { if (!g[i]) continue; flag++; if (hungary(i)) ans++; } printf("%d\n",tot-ans/2); return 0; }