匈牙利算法(最大独立集) - 骑士放置 - AcWing 378

匈牙利算法(最大独立集) - 骑士放置 - AcWing 378

给定一个 N*M 的棋盘,有一些格子禁止放棋子。

问棋盘上最多能放多少个不能互相攻击的骑士(国际象棋的“骑士”,类似于中国象棋的“马”,按照“日”字攻击,但没有中国象棋“别马腿”的规则)。

输入格式

第一行包含三个整数N,M,T,其中T表示禁止放置的格子的数量。

接下来T行每行包含两个整数x和y,表示位于第x行第y列的格子禁止放置,行列数从1开始。

输出格式

输出一个整数表示结果。

数据范围

1 ≤ N , M ≤ 100 1≤N,M≤100 1N,M100

输入样例:

2 3 0

输出样例:

4

分析:

最大独立集: 选 择 图 中 最 多 的 点 放 入 一 个 集 合 中 , 集 合 内 部 任 意 两 点 之 间 没 有 边 。 选择图中最多的点放入一个集合中,集合内部任意两点之间没有边。

最大团: 选 择 图 中 最 多 的 点 加 入 一 个 集 合 中 , 集 合 内 部 任 意 两 点 之 间 有 边 。 即 找 出 一 个 点 数 最 多 的 完 全 图 。 选择图中最多的点加入一个集合中,集合内部任意两点之间有边。即找出一个点数最多的完全图。

在 二 分 图 中 , 求 最 大 独 立 集 , 在二分图中,求最大独立集,

等 价 于 去 掉 最 少 的 点 , 使 得 剩 下 的 点 相 互 之 间 都 不 连 通 。 等价于去掉最少的点,使得剩下的点相互之间都不连通。 使

要 使 得 去 掉 的 点 最 少 , 那 么 每 删 去 一 个 点 , 就 必 须 破 坏 一 条 边 。 要使得去掉的点最少,那么每删去一个点,就必须破坏一条边。 使

等 价 于 找 到 最 小 点 覆 盖 。 等价于找到最小点覆盖。

等 价 于 求 最 大 匹 配 。 等价于求最大匹配。

代码:

#include<iostream>
#include<cstring>
#include<algorithm>

#define P pair<int,int>
#define x first
#define y second

using namespace std;

const int N=110;

int n,m,k;
bool g[N][N],st[N][N];
P match[N][N];
int dir[8][2]={{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2}};


bool Find(int x,int y)
{
    for(int i=0;i<8;i++)
    {
        int a=x+dir[i][0],b=y+dir[i][1];
        if(a<1||a>n||b<1||b>m) continue;
        if(st[a][b] || g[a][b]) continue;
        st[a][b]=true;
        
        P t=match[a][b];
        if(t.x==0 || Find(t.x,t.y))
        {
            match[a][b]={x,y};
            return true;
        }
    }
    return false;
}

int main()
{
    cin>>n>>m>>k;
    for(int i=0;i<k;i++)
    {
        int a,b;
        cin>>a>>b;
        g[a][b]=true;
    }
    
    int res=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if((i+j)%2 && !g[i][j])
            {
                memset(st,false,sizeof st);
                if(Find(i,j)) res++;
            }
            
    cout<<n*m-k-res<<endl;
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值