【bzoj3175】[Tjoi2013]攻击装置
每两个能互相攻击且能放置的点连一条双向边,然后跑二分图最大点独立集即可
#include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> using namespace std; typedef long long LL; #define M 80010 #define N 210 struct edge { int to,next; }e[M<<1]; int head[M<<1]; int cnt; int ly[M]; int a[N][N],flag[M]; char s[N]; int dx[]={1,1,2,2}; int dy[]={2,-2,1,-1}; int n,q; int tot,ans; void link(int x,int y) { e[++cnt]=(edge){y,head[x]}; head[x]=cnt; } bool find(int x) { for (int i=head[x];i;i=e[i].next) { int t=e[i].to; if (flag[t]!=q) { flag[t]=q; if (!ly[t] || find(ly[t])) { ly[t]=x; return true; } } } return false; } int main() { scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%s",s+1); for (int j=1;j<=n;j++) if (s[j]=='0') a[i][j]=++tot; else a[i][j]=0; } for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) if (a[i][j]) for (int k=0;k<4;k++) { int x=i+dx[k],y=j+dy[k]; if (x<1 || x>n || y<1 || y>n) continue; if (a[x][y]) link(a[i][j],a[x][y]),link(a[x][y],a[i][j]); } for (int i=1;i<=tot;i++) { q++; if (find(i)) ans++; } printf("%d\n",tot-ans/2); return 0; }