[二分图]Knight

题目描述
一张大小为n*n的国际象棋棋盘,上面有一些格子被拿走了,棋盘规模n不超过200。马的攻击方向如下图,其中S处为马位置,标有X的点为该马的攻击点。

你的任务是确定在这个棋盘上放置尽可能多的马,并使他们不互相攻击。

Output
第一行有两个整数n,k
接下来k行每行两个整数x,y表示去掉的格子

分析
想当年我刚学DFS做跳马的时候想做这题←_←
这题是二分图例题里来的,那么肯定是二分图(滑稽)
好的不扯了,二分图中最大独立集的概念是顶点数-最小覆盖(即最大匹配)的到最大独立集中元素的个数
然后我们看一看,这题数据为200*200的矩阵,那么独立集的顶点数则为40000个。
什么?40000^2谁开得起这样大的数组?
那么我们必须考虑其他的方法。
但是我们可以明显地看出,最多最多的情况下,也只能放置20000个棋子(或更少)
于是我想到了几天前搜这题的时候讲到的一个奇偶建图的概念,即建图方式为(i+j)%2,若为1,做二分图下面的,若为0,做二分图上面的。
那么就很简单了。
记得顶点要减去被去掉的格子

#include 
#include 
#include 
using namespace std;
int n,m;
int f[20001],map[201][201],xl[20001][2],dx[8],dy[8];
bool r[20001],q[201][201];
int i,j,x,y,k,ans;
bool fin(int a)
{
    int i,d,w1,w2;
    for (i=0;i<8;i++)
    {
        w1=xl[a][0]+dx[i];w2=xl[a][1]+dy[i];
        if (w1<1||w1>n||w2<1||w2>n||q[w1][w2]||r[map[w1][w2]]) continue;
        d=f[map[w1][w2]];f[map[w1][w2]]=a;r[map[w1][w2]]=1;
        if (d==0||fin(d)) return true;
        f[map[w1][w2]]=d;
    }
    return false;
}
int main()
{
    scanf("%d%d",&n,&m);
    dx[0]=1;dx[1]=1;dx[2]=-1;dx[3]=-1;dx[4]=-2;dx[5]=-2;dx[6]=2;dx[7]=2;
    dy[0]=-2;dy[1]=2;dy[2]=-2;dy[3]=2;dy[4]=1;dy[5]=-1;dy[6]=1;dy[7]=-1;
    for (i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        q[x][y]=1;
    }
    x=0;y=0;
    for (i=1;i<=n;i++)
    for (j=1;j<=n;j++)
    if (!q[i][j])
    {
        if ((i+j)%2)
        {
            x++;
            map[i][j]=x;
        }
        else
        {
            y++;
            map[i][j]=y;
            xl[y][0]=i;
            xl[y][1]=j;
        }
    }
    for (i=1;i<=y;i++)
    {
        memset(r,0,sizeof(r));
        if (fin(i)) ans++;
    }
    k=n*n-m-ans;
    printf("%d\n",k);
}

你可能感兴趣的:([二分图]Knight)