24.骑士共存问题

P3355 骑士共存问题

题目描述

在一个 n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示。棋盘上某些方格设置了障碍,骑士不得进入

对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑士,使得它们彼此互不攻击

输入输出格式

输入格式:

 

第一行有 2 个正整数n 和 m (1<=n<=200, 0<=m<n2),分别表示棋盘的大小和障碍数。接下来的 m 行给出障碍的位置。每行 2 个正整数,表示障碍的方格坐标。

输入样例#1: 复制

3 2
1 1
3 3

输出样例#1: 复制

5

建图:整个棋盘可以分为黑白两种颜色(坐标相加奇偶性)。显然是让求二分图最大独立集。在二分图的基础上,相互攻击到的可以连边即可!lyd大佬说了 二分图用dinic跑比较快~  那就走起~~

using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define oo cout<<"!!!"<<endl;
typedef long long ll;
typedef unsigned long long ull;
#define ms(s) memset(s, 0, sizeof(s))
const int inf = 0x3f3f3f3f;
//head

const int maxn = 1e6+11;

int head[maxn],ver[maxn],edge[maxn],nxt[maxn],d[maxn],tot;
int n,m,s,t,maxflow;

void add(int x,int y,int z)
{
    ver[++tot] = y;edge[tot] = z;nxt[tot] = head[x],head[x] = tot;
    ver[++tot] = x;edge[tot] = 0;nxt[tot] = head[y],head[y] = tot;
}

bool bfs()
{
    ms(d);
    queue<int>q;
    q.push(s);
    d[s] = 1;
    while(!q.empty())
    {
        int x = q.front();q.pop();
        for(int i = head[x];i;i = nxt[i])
        {
            if(edge[i] && !d[ver[i]])
            {
                q.push(ver[i]);
                d[ver[i]] = d[x] + 1;
                if(ver[i] == t)return 1;
            } 
        }
    }
    return 0;
}

int dinic(int x,int flow)
{
    if(x == t)return flow;
    int rest = flow,k;
    for(int i = head[x];i && rest;i = nxt[i])
    {
        if(edge[i] && d[ver[i]] == d[x]+1)
        {
            k = dinic(ver[i],min(rest,edge[i]));
            if(!k)d[ver[i]] = 0;
            edge[i] -= k;
            edge[i^1] +=k;  
            rest -= k;
        }
    }
    return flow - rest;
}

int dx[] = {1,1,2,2,-1,-1,-2,-2},dy[] = {-2,2,1,-1,2,-2,1,-1};
bool mp[222][222];
inline int id(int x,int y){return (x-1)*n + y;}

int main() 
{
    cin>>n>>m;
    int sum = n*n-m;
    t = n*n + 2;
    s = 0;
    tot = 1;
    while(m--)
    {
        int x,y;
        scanf("%d%d",&x,&y);mp[x][y] =1;
    }

    rep(i,1,n+1)
        rep(j,1,n+1)
        {
            if(mp[i][j])continue;
            if((i+j)&1)                                                             
            {
                add(s,id(i,j),1);
                rep(k,0,8)
                {
                    int x = i + dx[k],y = j + dy[k];
                    if(x < 1 || y < 1 || x > n || y >n || mp[x][y])continue;
                    add(id(i,j),id(x,y),inf);   
                }
            }
            else add(id(i,j),t,1);
        }
    int flow = 0;

    while(bfs())
        while(flow = dinic(s,inf)) maxflow += flow;
    cout << sum - maxflow << endl;
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值