题目链接: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;
}