众所周知,马后炮是中国象棋中很厉害的一招必杀技。”马走日字”。本来,如果在要去的方向有别的棋子挡住(俗称”蹩马腿”),则不允许走过去。为了简化问题,我们不考虑这一点。马跟马显然不能在一起打起来,于是rly在一天再次借来了许多许多的马在棋盘上摆了起来……但这次,他实在没兴趣算方案数了,所以他只想知道在N×M的矩形方格中摆马使其互不吃到的情况下的最多个数。但是,有一个很不幸的消息,rly由于玩得太Happy,质量本来就不好的棋盘被rly弄坏了,不过幸好只是破了其中的一些格子(即不能再放子了),问题还是可以继续解决的。
这道题同bzoj 3175一样,但问题是如果是普通的二分图匹配的话,这里就不会像bzoj 3175那样A,会T。要加什么黑白染色,但本蒟蒻不会啊。然后神奇地发现了改了一下dx,dy数组内数字的位置,就会快很多。太玄学了。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
using namespace std;
struct node
{
int x,y,next;
}a[400010];int len,last[40010];
void ins(int x,int y)
{
len++;
a[len].x=x;a[len].y=y;
a[len].next=last[x];last[x]=len;
}
int dx[8]={-1,-2, 1, 2,-1,-2,1,2};
int dy[8]={-2,-1,-2,-1, 2, 1,2,1};
int chw[40010],sd;
int s[210][210],match[40010];
int sp[210][210];
bool find_muniu(int x)
{
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(chw[y]!=sd)
{
chw[y]=sd;
if(match[y]==0 || find_muniu(match[y])==true)
{
match[y]=x;
return true;
}
}
}
return false;
}
int main()
{
int n,m,ss=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&s[i][j]);
if(s[i][j]==0)sp[i][j]=++ss;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(s[i][j]==0)
{
for(int k=0;k<8;k++)
{
int xx=i+dx[k],yy=j+dy[k];
if(xx>=1 && xx<=n && yy>=1 && yy<=m && s[xx][yy]==0)ins(sp[i][j],sp[xx][yy]);
}
}
}
}
int ans=0;
for(int i=1;i<=ss;i++)
{
sd++;
if(find_muniu(i)==true)ans++;
}
printf("%d\n",ss-ans/2);
return 0;
}