#bzoj-Balic2001#棋盘上的骑士(Hungary)

[Balic2001]棋盘上的骑士

时间限制: 10 Sec  内存限制: 64 MB

题目描述

一个N*N的棋盘上,有一些小方格被拿走了,不能放置骑士,其它位置可以放。现要在棋盘上放若干骑士,要求任一个骑士都不能在其他骑士的攻击点上。请算出棋盘上最多能有几个骑士。骑士攻击范围如图所示(S是骑士的位置,X表示马的攻击点) 《#bzoj-Balic2001#棋盘上的骑士(Hungary)》

输入

第一行包含2个整数n和m,用单个的空格分开,1<=n<=200 , 0<=m < 40000;n 是国际象棋棋盘的大小,m是被拿走的格子数。 下面m行每行包含 2 个整数:x和y,用单个的空格分开,1<=x,y<=n,这些是被拿走的格子的坐标。 棋盘的左上角的坐标是(1,1),右下角是(n,n)。拿走的格子没有重复的。

输出

一个整数,它应该是能放在国际象棋棋盘上的互不攻击对方的马的最大的数量。

样例输入

3 2 1 1 3 3 

样例输出

5

一道很坑的匈牙利匹配题,坑在搜索顺序上

首先建图,将下标奇偶性相同的格子看做一部,余下的看做另一部,根据象棋规则,必有X部向Y部连边的是非法状态(即两个位置不共存)

所以检查冲突匹配数,剩下的为答案

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
 
const int Max = 205;
 
struct node{
    int v, nxt;
}edge[Max * Max << 3];
 
int N, T, cnt;
int fir[Max * Max], match[Max * Max];
int dd[8][2] = {{-2, -1}, {-2, 1}, {-1, -2}, {-1, 2}, {1, -2}, {1, 2}, {2, -1}, {2, 1}};
bool vis[Max * Max], P[Max][Max];
 
void addedge(int a, int b){edge[++ cnt].v = b, edge[cnt].nxt = fir[a], fir[a] = cnt;}
 
bool inarea(int a, int b){
    if(a < 1 || b < 1 || a > N || b > N || P[a][b]) return 0;
    return 1;
}
 
bool Hungary(int i){
    for(int j = fir[i]; j; j = edge[j].nxt) if(!vis[edge[j].v]){
        vis[edge[j].v] = 1;
        if(! match[edge[j].v] || Hungary(match[edge[j].v])){
            match[edge[j].v] = i;
            return 1;
        }
    }
    return 0;
}
 
int main(){
    cnt = 1;
    scanf("%d%d", &N,&T);
    int Ans = N * N - T;
    int x, y;
    while(T --){
        scanf("%d%d", &x, &y);
        P[x][y] = 1;
    }
    for(int i = 1;i <= N; ++ i)
        for(int j = 1; j <= N; ++ j)
            if(! P[i][j] && (i & 1) == (j & 1)){
                int p1 = (i - 1) * N + j;
                for(int k = 0; k < 8; ++ k){
                    int xx = i + dd[k][0], yy = j + dd[k][1];
                    if(inarea(xx, yy)){
                        int p2 = (xx - 1) * N + yy;
                        addedge(p1, p2);
                    }
                }
            }
    for(int i = 1; i <= N; ++ i)
        for(int j = 1; j <= N; ++ j)
            if(! P[i][j] && (i & 1) == (j & 1)){
                memset(vis, 0, sizeof(vis));
                Ans -= Hungary((i - 1) * N + j);
            }
    printf("%d\n", Ans);
    return 0;
}
    原文作者:骑士周游问题
    原文地址: https://blog.csdn.net/its_elaine/article/details/74452410
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞