Description
众所周知,马后炮是中国象棋中很厉害的一招必杀技。"马走日字"。本来,如果在要去的方向有别的棋子挡住(俗
称"蹩马腿"),则不允许走过去。为了简化问题,我们不考虑这一点。马跟马显然不能在一起打起来,于是rly在
一天再次借来了许多许多的马在棋盘上摆了起来……但这次,他实在没兴趣算方案数了,所以他只想知道在N×M的
矩形方格中摆马使其互不吃到的情况下的最多个数。但是,有一个很不幸的消息,rly由于玩得太Happy,质量本来
就不好的棋盘被rly弄坏了,不过幸好只是破了其中的一些格子(即不能再放子了),问题还是可以继续解决的。
Input
一行,两个正整数N和M。
接下来N行,每行M个数,要么为0,表示没坏,要么为1,表示坏了。
N<=200,M<=200
Output
一行,输出最多的个数。
Sample Input
2 3
0 1 0
0 1 0
0 1 0
0 1 0
Sample Output
2
【解析】
最大独立集
把能攻击到的地方连边
总点数-最大匹配数=最大独立集
但是!!二分匹配出来的最大匹配数要/2
因为x能攻击y,连一条边;y也能攻击x,也会连一条边
(额~bzoj3175和bzoj4808没什么区别,数据范围都一样,只是m*n的棋盘和n*n的棋盘而已)
【bzoj4080】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
int x,y,next;
}a[410000];int len,last[41000];
void ins(int x,int y)
{
len++;
a[len].x=x;a[len].y=y;
a[len].next=last[x];last[x]=len;
}
int match[41000];
bool chw[41000];
bool find_muniu(int x)
{
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(chw[y]==false)
{
chw[y]=true;
if(match[y]==0 || find_muniu(match[y])==true)
{
match[y]=x;
return true;
}
}
}
return false;
}
int d[210][210];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
len=0;memset(last,0,sizeof(last));
memset(d,-1,sizeof(d));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++) scanf("%d",&d[i][j]);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(d[i][j]==0)
{
int now=(i-1)*m+j;
if(j-1>=1 && i-2>=1 && d[i-2][j-1]==0) ins(now,now-m-m-1);
if(j-2>=1 && i-1>=1 && d[i-1][j-2]==0) ins(now,now-m-2);
if(j+1<=m && i-2>=1 && d[i-2][j+1]==0) ins(now,now-m-m+1);
if(j+2<=m && i-1>=1 && d[i-1][j+2]==0) ins(now,now-m+2);
if(j-1>=1 && i+2<=n && d[i+2][j-1]==0) ins(now,now+m+m-1);
if(j-2>=1 && i+1<=n && d[i+1][j-2]==0) ins(now,now+m-2);
if(j+1<=m && i+2<=n && d[i+2][j+1]==0) ins(now,now+m+m+1);
if(j+2<=m && i+1<=n && d[i+1][j+2]==0) ins(now,now+m+2);
}
}
}
int ans=0,k=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(d[i][j]==0)
{
k++;
memset(chw,false,sizeof(chw));
int now=(i-1)*m+j;
if(find_muniu(now)==true) ans++;
}
}
}
printf("%d\n",k-ans/2);
return 0;
}
【bzoj3175】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
int x,y,next;
}a[410000];int len,last[41000];
void ins(int x,int y)
{
len++;
a[len].x=x;a[len].y=y;
a[len].next=last[x];last[x]=len;
}
int match[41000];
bool chw[41000];
bool find_muniu(int x)
{
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(chw[y]==false)
{
chw[y]=true;
if(match[y]==0 || find_muniu(match[y])==true)
{
match[y]=x;
return true;
}
}
}
return false;
}
char s[210];
int d[210][210];
int main()
{
int n;
scanf("%d",&n);
len=0;memset(last,0,sizeof(last));
memset(d,-1,sizeof(d));
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
for(int j=1;j<=n;j++)
{
if(s[j]=='0') d[i][j]=0;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(d[i][j]==0)
{
int now=(i-1)*n+j;
if(j-1>=1 && i-2>=1 && d[i-2][j-1]==0) ins(now,now-n-n-1);
if(j-2>=1 && i-1>=1 && d[i-1][j-2]==0) ins(now,now-n-2);
if(j+1<=n && i-2>=1 && d[i-2][j+1]==0) ins(now,now-n-n+1);
if(j+2<=n && i-1>=1 && d[i-1][j+2]==0) ins(now,now-n+2);
if(j-1>=1 && i+2<=n && d[i+2][j-1]==0) ins(now,now+n+n-1);
if(j-2>=1 && i+1<=n && d[i+1][j-2]==0) ins(now,now+n-2);
if(j+1<=n && i+2<=n && d[i+2][j+1]==0) ins(now,now+n+n+1);
if(j+2<=n && i+1<=n && d[i+1][j+2]==0) ins(now,now+n+2);
}
}
}
int ans=0,k=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(d[i][j]==0)
{
k++;
memset(chw,false,sizeof(chw));
int now=(i-1)*n+j;
if(find_muniu(now)==true) ans++;
}
}
}
printf("%d\n",k-ans/2);
return 0;
}