ssl1344-Knights【最大独立集,最大匹配,图论】

正题


大意

求在一个扣掉m个格子的n*n的棋盘能放置的最多的马。
ssl1344-Knights【最大独立集,最大匹配,图论】_第1张图片


解题思路

求最大独立集就好了,最大独立集=点数-最大匹配数。最重要的是如何建图。定义一个数组point[i][j]表示点的编号。但是如果这样的话就会O(n4)O(n4)就会超时。现在我们把棋盘从左到右后从上到下标号,那这样奇数就攻击不到奇数,偶数就攻击不到偶数,然后分两边构图,就可以O(n4/2)O(n4/2)


代码

#include
#include
using namespace std;
int one,two,n,m,link[20001],ddx,ddy,w,s,zx[20001],zy[20001],point[201][201];
int tot,dx[8]={1,1,-1,-1,2,2,-2,-2},dy[8]={2,-2,2,-2,1,-1,1,-1};
bool a[201][201],cover[20001];
bool find(int i)//求最大匹配
{
    int k=0;
    for (int j=0;j<8;j++)
    {
        if (zx[i]+dx[j]<1 || zy[i]+dy[j]<1 || zx[i]+dx[j]>n || zy[i]+dy[j]>n) continue;
        k=point[zx[i]+dx[j]][zy[i]+dy[j]];//记录
        if (!a[zx[i]+dx[j]][zy[i]+dy[j]] && !cover[k])
        {
            int q=link[k];
            link[k]=i;
            cover[k]=true;
            if (!q || find(q)) return true;
            link[k]=q;
        }
    }
    return false;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    { 
      scanf("%d%d",&ddx,&ddy);
      a[ddx][ddy]=true;
    }
    for (int i=1;i<=n;i++)
      for (int j=1;j<=n;j++)
      {
          if (!a[i][j])
          {
            if ((i+j)%2==0) point[i][j]=++two;//标号
            else 
            {
              point[i][j]=++one;//标号
              zx[one]=i;//记录坐标
              zy[one]=j;
            }
          }
      }
    s=0;
    for (int i=1;i<=one;i++)
    {
      memset(cover,0,sizeof(cover));
      if (find(i)) s++;//找最大匹配数
    }
    printf("%d",n*n-m-s);
}

转载于:https://www.cnblogs.com/sslwyc/p/8847849.html

你可能感兴趣的:(ssl1344-Knights【最大独立集,最大匹配,图论】)