SSL_1344 knights

题意

在一个n*n的矩阵中,放入尽可能多的马,使它们都不会互相攻击,这个矩阵中可能有几个块是会被挖掉的,那里就不能放马。

思路

这题就是求一个二分图的最大独立集。

定理:U=V-M;V=顶点数,M=最大匹配数(最小覆盖数),U=最大独立集。

这道题难点在于我们怎么去建图。首先我们把点数为奇数的和偶数的分别标开,因为点数为奇数的不会吃到点数为奇数的,所以这样不会矛盾,所以我们这样子做的话会减少之后找增广链的次数;然后,我们就从偶数点上去找增广链然后统计答案就好了。

代码

#include
#include
using namespace std;
int n,m,k[201][201],map[201][201],odd,eve,link[30001],vis[30001],ans,a,b,xa,ya;
struct node{
    int x,y;
}c[30001];
short dx[9]={0,1,1,-1,-1,2,2,-2,-2},dy[9]={0,2,-2,2,-2,1,-1,1,-1};
int find(int x)
{
    for (int i=1;i<=8;i++)
    {
        xa=c[x].x+dx[i];ya=c[x].y+dy[i];//找可以被吃掉的点
        int j=map[xa][ya];//j为当前点能吃到的点的编号
        if (!(xa<1||xa>n||ya<1||ya>n//判断范围
        ||(vis[map[xa][ya]]||k[xa][ya])))//没有访问过也没有被扣掉
        {
            int q=link[j];
            link[j]=x;
            vis[j]=1;
            if (find(q)||!q) return 1;
            link[j]=q;
        }
    }
    return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        k[a][b]=1;//k表示当前的方块是否被扣掉
    }
    for (int i=1;i<=n;i++)
      for (int j=1;j<=n;j++)
        if (!k[i][j])
        {
            if ((i+j)%2) map[i][j]=++odd;
            else 
            {
                map[i][j]=++eve;//记录编号
                c[eve].x=i;
                c[eve].y=j;//记录坐标
            }
        }
    for (int i=1;i<=eve;i++)//从偶数点去找
    {
        memset(vis,0,sizeof(vis));
        if (find(i)) ans++;//最大匹配数
    }
    printf("%d",n*n-m-ans);//最大独立集(要减去扣掉的点)
}

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