BZOJ4808 马

这道题的题意简化一下就是在好格子中找到最大的一个格子集合,使得集合内的格子之间没有边,那就是最大独立集呗,二分染色然后最大匹配,然后非常emmm的就是要用时间戳更新vis数组,不能 每次都清空,不然会T到飞起

代码

//By AcerMo
#include
#include
#include
#include
#include
using namespace std;
const int M=1e6;
int n,m,sum,ti,e;
int to[M],nxt[M],head[M],cnt;
int x[]={1,2,-1,-2,-1,2,1,-2};
int y[]={2,1,-2,-1,2,-1,-2,1};
int jud[205][205],id[205][205],vis[M],mat[M];
void add(int x,int y)
{
    to[++cnt]=y;nxt[cnt]=head[x];head[x]=cnt;
	return ;
}
bool tmid(int x)
{
    for (int i=head[x];i;i=nxt[i])
	{
    	int go=to[i];
        if (vis[go]!=ti)
		{
            vis[go]=ti;
            if (!mat[go]||tmid(mat[go])) 
			return mat[go]=x,1;
        }
    }
    return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
    for (int k=1;k<=m;k++)
	{
        scanf("%d",&jud[i][k]);
        sum+=(!jud[i][k]);
        id[i][k]=++e;
    }
    for (int i=1;i<=n;i++)
    for (int k=1;k<=m;k++)
    if (((i+k)&1)&&!jud[i][k])
    for (int j=0;j<8;j++) 
    {
    	int xx=i+x[j],yy=k+y[j];
    	if (xx>n||xx<1||yy>m||yy<1||jud[xx][yy]) continue; 
    	add(id[i][k],id[xx][yy]);
	}
    for (int i=1;i<=n;i++)
    for (int k=1;k<=m;k++)
    if (!jud[i][k] && ((i+k)&1))
    ti=id[i][k],sum-=tmid(ti);
    printf("%d",sum);
    return 0;
}

 

你可能感兴趣的:(图论-二分图)