[洛谷 P1263] 宫廷守卫 --- 二分图最大匹配

传送门:洛谷 P1263


题目描述

从前有一个王国,这个王国的城堡是一个矩形,被分为M×N个方格。一些方格是墙,而另一些是空地。这个王国的国王在城堡里设了一些陷阱,每个陷阱占据一块空地。

一天,国王决定在城堡里布置守卫,他希望安排尽量多的守卫。守卫们都是经过严格训练的,所以一旦他们发现同行或同列中有人的话,他们立即向那人射击。因此,国王希望能够合理地布置守卫,使他们互相之间不能看见,这样他们就不可能互相射击了。守卫们只能被布置在空地上,不能被布置在陷阱或墙上,且一块空地只能布置一个守卫。如果两个守卫在同一行或同一列,并且他们之间没有墙的话,他们就能互相看见。(守卫就像象棋里的车一样)

你的任务是写一个程序,根据给定的城堡,计算最多可布置多少个守卫,并设计出布置的方案。


分析

除去墙的存在,这个就是标准的二分图模型了,横纵坐标连边即可。
本题同理,只需要处理一下入读即可,有墙的话,视为换行/列。
方案输出:匹配的时候顺便记录匹配边即可。读入的时候记录一下边所代表的点。


代码

#include <cstdio>
#include <cstdlib>
#include <cstring>

#define IL inline

using namespace std;

IL int read()
{
    char c = getchar();
    int sum = 0 ,k = 1;
    for(;'0' > c || c > '9'; c = getchar())
        if(c == '-') k = -1;
    for(;'0' <= c && c <= '9'; c = getchar()) sum = sum * 10 + c - '0';
    return sum * k;
}

int n, m;
int mp[205][205];
int px[205][205];

struct node
{
    int x, y;
    IL node(int x_ = 0, int y_ = 0)
    {
        x = x_; y = y_;
    }
}pos[40005];

int to[40005], nxt[40005];
int cnt, last[20005];
IL void add(int u, int v)
{
    to[++cnt] = v; nxt[cnt] = last[u]; last[u] = cnt;
}

int match[20005];
int mark[20005];
bool vis[20005];

IL bool dfs(int u)
{
    for(int i = last[u], v; (v = to[i]); i = nxt[i])
    if(!vis[v])
    {
        vis[v] = 1;
        if(!match[v] || dfs(match[v]))
        {
            match[v] = u;
            mark[v] = i;
            return 1;
        }
    }
    return 0;
}

IL int max_flow()
{
    int sum = 0;
    for(int i = 1; i <= m; ++i)
    {
        memset(vis, 0, sizeof(vis));
        if(dfs(i)) ++sum;
    }
    return sum;
}

IL void wri()
{
    for(int i = 1; i <= n; ++i)
    if(mark[i])
        printf("%d %d\n", pos[mark[i]].x, pos[mark[i]].y);
}

int main()
{
    int l = read(), c = read();
    
    for(int i = 1, flag; i <= l; ++i)
    {
    	flag = 1;
    	for(int j = 1; j <= c; ++j)
    	{
    		mp[i][j] = read();
    		if(mp[i][j] == 2) flag = 1; else
    		if(!mp[i][j])
    		{
    			if(flag) { ++n; flag = 0; }
    			px[i][j] = n;
    		}
    	}
    }
    
    for(int j = 1, flag; j <= c; ++j)
    {
    	flag = 1;
    	for(int i = 1; i <= l; ++i)
    	{
    		if(mp[i][j] == 2) flag = 1; else
    		if(!mp[i][j])
    		{
    			if(flag) { ++m; flag = 0; }
    			add(m, px[i][j]); pos[cnt] = node(i, j);
    		}
    	}
    }
    
    printf("%d\n", max_flow());
    
    wri();
    
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值