SSL1344 Knights【二分图匹配】【匈牙利算法】

SSL1344 Knights【二分图匹配】【匈牙利算法】_第1张图片
对于本题来说,相互攻击的位置肯定不能同时存在两个马。
如果我们把两个相互攻击的位置连一条边,从而构成一个图。
那么相邻的两个点不能同时选,也就是求最大独立集
所以,我们可以把此题转化成最大匹配问题。
这道题我们需要黑白点覆盖,因为这是国际象棋,黑点只能跳白点,白点只能跳黑点。
我们考虑黑点连白点建立一个二分图
如何建?如果当前点是黑点,就让当前点分八个点拓展到其它点并建边 。
用不了坐标建边,就用编号建边。推一推可得点的编号为: ( i − 1 ) ∗ n + j (i-1)*n+j (i1)n+j
然后正常匈牙利跑最大匹配即可。
当然,由于是求最大独立集,所以:
答案 = = = 顶点数 − - 拿去的格子 − - 最大匹配

代码

#include
#include
#include
#include
#include
using namespace std;

int dx[9]={0,1,1,-1,-1,2,2,-2,-2};
int dy[9]={0,2,-2,2,-2,1,-1,1,-1};
int b[3010][3010],a[3010][3010],v[40200],link[1000010],ls[1000010];
int n,m,x,y,tot,ans;

struct node
{
	int y,next;
}map[1000010];
void add(int x,int y)
{
	map[++tot].y=y;
	map[tot].next=ls[x];
	ls[x]=tot;
}
int dfs(int x)  //找最大匹配
{
	for(int i=ls[x]; i; i=map[i].next)
	 {
	 	int y=map[i].y;
	 	if(!v[y])
	 	 {
	 	 	v[y]=1;
	 	 	int fa=link[y];
	 	 	link[y]=x;
	 	 	if(fa==0||dfs(fa))
	 	 	  return 1;
	 	 	link[y]=fa;
	 	 }
	 }
	return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1; i<=m; i++)
     {
     	scanf("%d%d",&x,&y);
     	b[x][y]=1;
     }
    for(int i=1; i<=n; i++)    //枚举每个点
     for(int j=1; j<=n; j++)
      if((i+j)%2==0&&!b[i][j])  //是黑点且格子没被拿走
       {
         for(int k=1; k<=8; k++)   //八个方向
          {
          	int xx=i+dx[k];
          	int yy=j+dy[k];
          	if(xx>=1&&xx<=n&&yy>=1&&yy<=n)
          	 if(!b[xx][yy])
          	   add((i-1)*n+j,(xx-1)*n+yy);
          }
       }
    for(int i=1; i<=n*n; i++)
     {
     	memset(v,0,sizeof(v));
     	if(dfs(i))
          ans++;
     }
    printf("%d",n*n-m-ans);
    return 0;
}

你可能感兴趣的:(题解(较高质量),#,匈牙利算法,二分图上的操作)