当前位置:网站首页>【ACWing】406. 放置机器人
【ACWing】406. 放置机器人
2022-08-01 23:47:00 【记录算法题解】
题目地址:
https://www.acwing.com/problem/content/description/408/
给出一个地图(网格),格子分为空地,草地,墙壁。要在空地上放能向上下左右 4 4 4个方向发射激光的机器人。墙壁能挡住激光,草地不能挡住激光也不能放机器人。在机器人不能互相打到对方的情况下,最多放置多少个机器人。
输入格式:
第一行包含整数 T T T,表示共有 T T T组测试数据。
每组数据第一行包含两个整数 m m m和 n n n,表示地图的大小为 m m m行 n n n列。
接下来 m m m行,每行包含 n n n个字符,用来描述整个地图。#代表墙壁,*代表草地,o代表空地。
输出格式:
每组测试数据在第一行输出Case :id,id是数据编号,从 1 1 1开始。
第二行包含一个整数,表示机器人的个数。
数据范围:
1 ≤ m , n ≤ 50 1≤m,n≤50 1≤m,n≤50
思路是二分图。将除了墙的地面定义一个等价关系叫行连通,两个非墙地面行连通当且仅当从一个能沿着行不经过墙走到另一个。那么这个等价关系可以将所有的非墙地面分为若干个等价类,我们把这些等价类编号为 1 , 2 , . . . , r 1,2,...,r 1,2,...,r;同理将列连通等价类编号为 1 , 2 , . . . , c 1,2,...,c 1,2,...,c。将 1 , 2 , . . . , r 1,2,...,r 1,2,...,r视为二分图左边的点, 1 , 2 , . . . , c 1,2,...,c 1,2,...,c视为二分图右边的点,如果某个行连通块和某个列连通块有交集,并且交集是o即空地,则将他们的编号之间连一条边。首先,这个二分图的任何一个匹配对应着一种放置方案:每条边对应一个空地,并且同一个行连通块里只能有一个机器人(因为会互相攻击),同一个列连通块也只能有一个机器人。其次,任意一个放置方案,对应一个匹配。所以最多的机器人放置方案一定就是二分图的最大匹配,从而可以用匈牙利算法来做。代码如下:
#include <cstring>
#include <iostream>
using namespace std;
const int N = 55, M = 2550;
int n, m, rcnt, ccnt;
char a[N][N];
int rid[N][N], cid[N][N];
int match[M];
bool vis[M];
int h[M], e[M], ne[M], idx;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
bool dfs(int u) {
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (vis[v]) continue;
vis[v] = true;
if (!match[v] || dfs(match[v])) {
match[v] = u;
return true;
}
}
return false;
}
int main() {
int T;
scanf("%d", &T);
for (int t = 1; t <= T; t++) {
memset(h, -1, sizeof h);
idx = 0;
memset(rid, 0, sizeof rid);
memset(cid, 0, sizeof cid);
scanf("%d%d", &m, &n);
for (int i = 1; i <= m; i++) scanf("%s", a[i] + 1);
rcnt = 1, ccnt = 1;
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++) {
if (a[i][j] != '#') {
while (j <= n && a[i][j] != '#') rid[i][j++] = rcnt;
rcnt++;
}
}
for (int j = 1; j <= n; j++)
for (int i = 1; i <= m; i++) {
if (a[i][j] != '#') {
while (i <= m && a[i][j] != '#') cid[i++][j] = ccnt;
ccnt++;
}
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
if (a[i][j] == 'o') add(rid[i][j], cid[i][j]);
int res = 0;
memset(match, 0, sizeof match);
// 行连通块的个数为rcnt - 1
for (int i = 1; i < rcnt; ++i) {
memset(vis, 0, sizeof vis);
if (dfs(i)) res++;
}
printf("Case :%d\n%d\n", t, res);
}
}
每组数据时间复杂度 O ( ( m n ) 2 ) O((mn)^2) O((mn)2),空间 O ( m n ) O(mn) O(mn)。
边栏推荐
- 递归:方法调用自身
- 路径压缩、、
- yay 报错 response decoding failed: invalid character ‘<‘ looking for beginning of value;
- 使用Jenkins做持续集成,这个知识点必须要掌握
- 切面打印调取的方法
- 机器学习文本分类
- 在CDH的hue上的oozie出现,提交 Coordinator My Schedule 时出错
- [C language advanced] file operation (2)
- FAST-LIO2 code analysis (2)
- The Spark of Sql join on the and and where
猜你喜欢

数据机构---第五章树与二叉树---二叉树的概念---应用题

技术分享 | 接口测试中如何使用Json 来进行数据交互 ?

2022 6th Strong Net Cup Part WP
![[C language advanced] file operation (2)](/img/4d/49d9603aeed16f1600d69179477eb3.png)
[C language advanced] file operation (2)

6134. 找到离给定两个节点最近的节点-力扣双百代码

邻接表与邻接矩阵

Thinkphp 5.0.24变量覆盖漏洞导致RCE分析

chrome copies the base64 data of an image
![[LeetCode304周赛] 两道关于基环树的题 6134. 找到离给定两个节点最近的节点,6135. 图中的最长环](/img/63/16de443caf28644d79dc6e6889e5dd.png)
[LeetCode304周赛] 两道关于基环树的题 6134. 找到离给定两个节点最近的节点,6135. 图中的最长环

C language - branch statement and loop statement
随机推荐
Flink学习第五天——Flink可视化控制台依赖配置和界面介绍
如何用Redis实现分布式锁?
async和await用法介绍
Calculate the distance between two points
problem solved
sys_kill system call
邻接表与邻接矩阵
【MySQL系列】MySQL数据库基础
Chrome书签插件,让你实现高效整理
Docker搭建Mysql主从复制
FAST-LIO2代码解析(二)
斜堆、、、
@WebServlet注解(Servlet注解)
20220725资料更新
Sql之各种Join
仿牛客网项目第三章:开发社区核心功能(详细步骤和思路)
如何进行数据库备份
Flink Yarn Per Job - 提交流程一
Programmer is still short of objects? A new one is enough
Deep Learning Fundamentals - Numpy-based Recurrent Neural Network (RNN) implementation and backpropagation training