bzoj3175[Tjoi2013] 攻击装置
题目链接:bzoj3175
题目大意:
给定一个01矩阵,其中你可以在0的位置放置攻击装置。每一个攻击装置(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)
求在装置互不攻击的情况下,最多可以放置多少个装置。
题解:
最大点独立集
%hyc
因为是日字形,所以可以根据x+y的奇偶性来分二分图。把能互相攻击到的连边,问最多能放多少个就是要求最大点独立集,构完图跑匈牙利求最大匹配然后用点数减一减就好了。
为什么我跑得比hyc慢那么多qwq
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define maxn 41000 int fx[8]={1,-1,1,-1,2,-2,2,-2}; int fy[8]={2,2,-2,-2,1,1,-1,-1}; struct node { int x,y,next; }a[maxn*8];int first[maxn],len; int ask[maxn],bf[maxn],tim; int m,ln[maxn],num[300][300]; void ins(int x,int y) { ++len;a[len].x=x;a[len].y=y; a[len].next=first[x];first[x]=len; } int ffind(int x) { for (int i=first[x];i!=-1;i=a[i].next) { int y=a[i].y; if (ask[y]!=tim) { ask[y]=tim; if (bf[y]==-1 || ffind(bf[y])) { bf[y]=x; return true; } } } return false; } int main() { int n,i,j,k,sum; int ans;char s[250]; scanf("%d\n",&n); len=sum=0; for (i=1;i<=n;i++) { gets(s); for (j=0;j<n;j++) if (s[j]=='0') {num[i][j+1]=++sum;bf[sum]=-1;} else num[i][j+1]=-1; } memset(first,-1,sizeof(first)); for (i=1;i<=n;i++) for (j=1;j<=n;j++) if (num[i][j]!=-1 && !((i+j)&1)) { for (k=0;k<8;k++) if (i+fx[k]>=1 && i+fx[k]<=n && j+fy[k]>=1 && j+fy[k]<=n && num[i+fx[k]][j+fy[k]]!=-1) ins(num[i][j],num[i+fx[k]][j+fy[k]]); m++;ln[m]=num[i][j]; } ans=tim=0; memset(ask,0,sizeof(ask)); // memset(bf,-1,sizeof(bf)); for (i=1;i<=m;i++) { tim++; if (ffind(ln[i])) ans++; } ans=sum-ans; printf("%d\n",ans); return 0; }