题目描述
给定一个01矩阵,其中你可以在0的位置放置攻击装置。 每一个攻击装置(x,y)(x,y)(x,y)都可以按照“日”字攻击其周围的8个位置(x−1,y−2),(x−2,y−1),(x+1,y−2),(x+2,y−1),(x−1,y+2),(x−2,y+1),(x+1,y+2),(x+2,y+1)(x-1,y-2),(x-2,y-1),(x+1,y-2),(x+2,y-1),(x-1,y+2),(x-2,y+1),(x+1,y+2),(x+2,y+1)(x−1,y−2),(x−2,y−1),(x+1,y−2),(x+2,y−1),(x−1,y+2),(x−2,y+1),(x+1,y+2),(x+2,y+1)。
求在装置互不攻击的情况下,最多可以放置多少个装置。
输入格式
第一行一个整数NNN,表示矩阵大小为N∗NN*NN∗N。
接下来NNN行每一行一个长度NNN的01串,表示矩阵。
输出格式
一个整数,表示在装置互不攻击的情况下最多可以放置多少个装置。
数据范围
30%30\%30%数据N<=50N<=50N<=50;
100%100\%100%数据N<=200N<=200N<=200。
分析
跟网络流24题中骑士共存问题一样,每个格子按横纵坐标之和的奇偶性分为黑点和白点,能够到达的两点之间,由黑点向白点建边,之后就是求这个二分图的最大独立集。有定理:二分图中最大独立集=总点数-二分图最小点覆盖=总点数-二分图最大匹配数,所以用匈牙利和Dinic都可以。但是为了放置出题人卡匈牙利,还是用Dinic更保险一些。用Dinic则需要从源点向二分图的左部节点建边,流量为1,由左部向右部建的边流量为1,再由右部节点向汇点建边,流量为1,这样源点到汇点的最大流即为该二分图的最大匹配数。
代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int N=205,M=N*N*N+10;
const int NN=N*N,Inf=0x7fffffff/2;
struct Edge {
int to,nxt,flow;
}e[M];
int h[NN],cnt,tot;
int n1[NN],n2[NN];
int tot1,tot2;
int n,ans,m,g[N][N],f[NN];
char s[N][N];
bool vis[NN];
int ntp[8][2]={{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}};
void Add(int x,int y,int z) {
e[++cnt]=(Edge){y,h[x],z};
h[x]=cnt;
}
struct Dinic {
int dis[NN];
bool Bfs(int s,int t) {
memset(dis,0,sizeof(dis));
queue<int> q;
q.push(s);
dis[s]=1;
while (!q.empty()) {
int x=q.front();
q.pop();
for (int i=h[x];i;i=e[i].nxt) {
int y=e[i].to;
if (e[i].flow&&!dis[y]) {
q.push(y);
dis[y]=dis[x]+1;
if (y==t) return 1;
}
}
}
return 0;
}
int Dfs(int x,int flow,int t) {
if (x==t) return flow;
int rest=flow,k;
for (int i=h[x];i&&rest;i=e[i].nxt) {
int y=e[i].to;
if (e[i].flow&&dis[y]==dis[x]+1) {
k=Dfs(y,min(rest,e[i].flow),t);
if (!k) dis[y]=0;
e[i].flow-=k;
e[i^1].flow+=k;
rest-=k;
}
}
return flow-rest;
}
int maxflow(int s,int t) {
int flow=0,ans=0;
while (Bfs(s,t))
while ((flow=Dfs(s,Inf,t))) ans+=flow;
return ans;
}
}dinic;
int main() {
scanf("%d",&n);
for (int i=1;i<=n;i++) {
scanf("%s",s[i]+1);
}
cnt=1;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) {
g[i][j]=++tot;
if (s[i][j]=='1') {
m++;
continue;
}
if (!((i+j)&1)) n1[++tot1]=g[i][j];
else n2[++tot2]=g[i][j];
}
for (int i=1;i<=n;i++) {
for (int j=((i&1)?1:2);j<=n;j+=2) {
if (s[i][j]=='1') continue;
for (int k=0;k<8;k++) {
int tx,ty;
tx=i+ntp[k][0];
ty=j+ntp[k][1];
if (tx<1||tx>n||ty<1||ty>n) continue;
if (s[tx][ty]=='1') continue;
Add(g[i][j],g[tx][ty],1);
Add(g[tx][ty],g[i][j],0);
}
}
}
for (int i=1;i<=tot1;i++) {
Add(0,n1[i],1);
Add(n1[i],0,0);
}
for (int i=1;i<=tot2;i++) {
Add(n2[i],tot+1,1);
Add(tot+1,n2[i],0);
}
printf("%d",n*n-m-dinic.maxflow(0,tot+1));
return 0;
}