[LeetCode] Contain Virus 包含病毒
A virus is spreading rapidly, and your task is to quarantine the infected area by installing walls.
The world is modeled as a 2-D array of cells, where 0 represents uninfected cells, and 1 represents cells contaminated with the virus. A wall (and only one wall) can be installed between any two 4-directionally adjacent cells, on the shared boundary.
Every night, the virus spreads to all neighboring cells in all four directions unless blocked by a wall. Resources are limited. Each day, you can install walls around only one region -- the affected area (continuous block of infected cells) that threatens the most uninfected cells the following night. There will never be a tie.
Can you save the day? If so, what is the number of walls required? If not, and the world becomes fully infected, return the number of walls used.
Example 1:
Input: grid =
[[0,1,0,0,0,0,0,1],
[0,1,0,0,0,0,0,1],
[0,0,0,0,0,0,0,1],
[0,0,0,0,0,0,0,0]]
Output: 10
Explanation:
There are 2 contaminated regions.
On the first day, add 5 walls to quarantine the viral region on the left. The board after the virus spreads is: [[0,1,0,0,0,0,1,1],
[0,1,0,0,0,0,1,1],
[0,0,0,0,0,0,1,1],
[0,0,0,0,0,0,0,1]] On the second day, add 5 walls to quarantine the viral region on the right. The virus is fully contained.
Example 2:
Input: grid =
[[1,1,1],
[1,0,1],
[1,1,1]]
Output: 4
Explanation: Even though there is only one cell saved, there are 4 walls built.
Notice that walls are only built on the shared boundary of two different cells.
Example 3:
Input: grid =
[[1,1,1,0,0,0,0,0,0],
[1,0,1,0,1,1,1,1,1],
[1,1,1,0,0,0,0,0,0]]
Output: 13
Explanation: The region on the left only builds two new walls.
Note:
- The number of rows and columns of
gridwill each be in the range[1, 50]. - Each
grid[i][j]will be either0or1. - Throughout the described process, there is always a contiguous viral region that will infect strictly moreuncontaminated squares in the next round.
这道题给了我们一个由0和1组成的二维数组,其中0表示健康细胞,而1表示病毒细胞,多个相邻的1组成了病毒细胞群,每天都会向周围扩散一圈,除非我们在其跟健康细胞之间建立隔离墙,这样其才会不会扩散。我们每天只能给一个病毒细胞群来建立隔离墙,其他的细胞群会进行扩散。问最终我们需要多少个隔离墙。这道题真的挺难,博主研究了好久才弄明白题目的意思。首先要明白一点,病毒细胞只会向上下左右四个方向相邻的健康细胞扩散。需要注意的一点是,需要的隔离墙的数量可能大于周围相邻的健康细胞,最明显的就是例子2中,只有一个健康细胞,但是需要四个隔离墙才能保护这个健康细胞不被感染。还有就是,我们需要隔离某个病毒细胞群的判定依据是其能感染的健康细胞的数量,而不是需要建的墙的数量或者病毒细胞的个数,这点很重要,博主之前没有注意这一点,导致fail了一个test case。所以我们要做的就是要求出每个病毒细胞群能感染的健康细胞的数量,其周围能建墙的地方,以及每个病毒细胞的位置。我们再其中选择能感染最多健康细胞的病毒细胞群进行建墙,建完墙后,我们将该群中的所有病毒细胞标记为-1,跟其他细胞区分出来。对于其他所有的病毒细胞群,将其周围能建墙的地方(即健康细胞)都标记为1,表示其现在已经被感染成了病毒细胞。然后再进行新的一轮循环检测,直到无法找出新的病毒细胞为止。
我们先找值为1的点,找到后,以其作为起点,进行BFS遍历,将和其相连的所有为1的点都找出来,在BFS遍历的过程中,如果我们检测到周围位置值为0,将其加入walls数组,表示这里可以建隔离墙,如果检测到周围位置为1,将其加入virus数组,表示这里是病毒细胞,注意起始位置也要提前加入virus数组。我们这里为了节省维度,将二维的坐标都encode成了一个int数字。BFS遍历结束后,我们根据walls数组来算出能感染的健康细胞的个数,因为我们前面提到过建隔离墙的位置可能大于健康细胞的个数,所以我们只要去除wall数组的重复项即可,利用HashSet的去重复项原理,然后将剩下的个数放入cells数组中。把cells,walls,和virus数组放入一个vector中,表示一个病毒细胞群的信息,再放入一个大数组all中,这样我们收集了所有病毒细胞群的信息后,可以根据可感染的健康细胞个数由多到少来排序,这样我们就把第一个病毒细胞群中所有virus数组的位置值变为-1,并且把可感染的健康细胞个数累加到结果res中。然后把后面所有的病毒细胞群中walls的位置值都变为1即可。当all数组为空时,跳出循环,表示没有检测到病毒细胞群或者全部都被感染了,参见代码如下:
class Solution {
public:
int containVirus(vector<vector<int>>& grid) {
int res = , m = grid.size(), n = grid[].size();
vector<vector<int>> dirs{{-,},{,},{,},{,-}};
while (true) {
unordered_set<int> visited;
vector<vector<vector<int>>> all;
for (int i = ; i < m; ++i) {
for (int j = ; j < n; ++j) {
if (grid[i][j] == && !visited.count(i * n + j)) {
queue<int> q{{i * n + j}};
vector<int> virus{i * n + j};
vector<int> walls;
visited.insert(i * n + j);
while (!q.empty()) {
auto t = q.front(); q.pop();
for (auto dir : dirs) {
int x = (t / n) + dir[], y = (t % n) + dir[];
if (x < || x >= m || y < || y >= n || visited.count(x * n + y)) continue;
if (grid[x][y] == -) continue;
else if (grid[x][y] == ) walls.push_back(x * n + y);
else if (grid[x][y] == ) {
visited.insert(x * n + y);
virus.push_back(x * n + y);
q.push(x * n + y);
}
}
}
unordered_set<int> s(walls.begin(), walls.end());
vector<int> cells{(int)s.size()};
all.push_back({cells ,walls, virus});
}
}
}
if (all.empty()) break;
sort(all.begin(), all.end(), [](vector<vector<int>> &a, vector<vector<int>> &b) {return a[][] > b[][];});
for (int i = ; i < all.size(); ++i) {
if (i == ) {
vector<int> virus = all[][];
for (int idx : virus) grid[idx / n][idx % n] = -;
res += all[][].size();
} else {
vector<int> wall = all[i][];
for (int idx : wall) grid[idx / n][idx % n] = ;
}
}
}
return res;
}
};
参考资料:
https://discuss.leetcode.com/topic/114208/c-dfs-12ms
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Contain Virus 包含病毒的更多相关文章
- [LeetCode] 749. Contain Virus 包含病毒
A virus is spreading rapidly, and your task is to quarantine the infected area by installing walls. ...
- [LeetCode] Contains Duplicate 包含重复值
Given an array of integers, find if the array contains any duplicates. Your function should return t ...
- Virus:病毒查杀
简介 小伙伴们,大家好,今天分享一次Linux系统杀毒的经历,还有个人的一些总结,希望对大家有用. 这次遇到的是一个挖矿的病毒,在挖一种叫门罗币(XMR)的数字货币,行情走势请看 https://ww ...
- Leetcode 600.不包含连续1的非负整数
不包含连续1的非负整数 给定一个正整数 n,找出小于或等于 n 的非负整数中,其二进制表示不包含 连续的1 的个数. 示例 1: 输入: 5 输出: 5 解释: 下面是带有相应二进制表示的非负整数&l ...
- hdu 2896 病毒侵袭 AC自动机(查找包含哪些子串)
病毒侵袭 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- 【HDU2896】病毒侵袭 AC自动机
[HDU2896]病毒侵袭 Problem Description 当太阳的光辉逐渐被月亮遮蔽,世界失去了光明,大地迎来最黑暗的时刻....在这样的时刻,人们却异常兴奋--我们能在有生之年看到500年 ...
- HDU2896 病毒侵袭 —— AC自动机
题目链接:https://vjudge.net/problem/HDU-2896 病毒侵袭 Time Limit: 2000/1000 MS (Java/Others) Memory Limit ...
- HDU2896 病毒侵袭
题目大意:给出若干病毒的特征码,不超过500个.每个病毒的特征码长度在20~200之间.现在有若干网站的源代码,要检测网站的源代码中是否包含病毒.网站的个数不超过1000个,每个网站的源代码长度在70 ...
- hdu2896 病毒侵袭 ac自动机
地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=2896 题目: 病毒侵袭 Time Limit: 2000/1000 MS (Java/Othe ...
随机推荐
- [poj1094]Sorting It All Out_拓扑排序
Sorting It All Out poj-1094 题目大意:给出一些字符串之间的大小关系,问能否得到一个唯一的字符串序列,满足权值随下标递增. 注释:最多26个字母,均为大写. 想法:显然,很容 ...
- KVM之七:KVM克隆
1.在克隆虚拟机之前,必须先暂停或者停掉kvm 虚拟机.以虚拟机 snale 为例,先暂停虚拟机,如下 [root@kvm ~ ::]#virsh list Id 名称 状态 ------------ ...
- 使用ADO.NET查询和操作数据库
String和StringBuilder 语法: //声明一个空的StringBuilder对象 StingBuilder对象名称 = new StringBuilder(); //声明一个Str ...
- Linux下ping,telnet,ssh命令的比较
ping工作在OSI模型的第三层,网络层. 主要用于测试到达目的主机的网络是否连接,不能检测某个端口是否开放. ping使用ICMP协议,不使用某个特定端口. 也可以 ping 域名 ,这样可以直接看 ...
- Property 'id' not found on type java.lang.String
改为 忘写了$符,取不出来,因此报错!
- 2017-2018-1 20155306 mypwd的实现
2017-2018-1 20155306 mypwd的实现 一.pwd的使用 功能: Linux中用 pwd 命令来查看"当前工作目录"的完整路径. 命令格式:pwd [选项] 命 ...
- Beta敏捷冲刺每日报告——Day2
1.情况简述 Beta阶段Scrum Meeting 敏捷开发起止时间 2017.11.2 00:00 -- 2017.11.3 00:00 讨论时间地点 2017.11.2 晚9:30,电话会议会议 ...
- PTA題目的處理(二)
題目7-1 計算分段函數[1] 1.實驗代碼 #include <stdio.h> int main() { float x,y; scanf("%f",&x) ...
- 201621123068 Week04-面向对象设计与继承
1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 答:继承.多态.重载.关键字.父类与子类 1.2 尝试使用思维导图将这些关键词组织起来. 2. 书面作业 1. 面向对象设计(大 ...
- DistBlockNet:A Distributed Blockchains-Based Secure SDN Architecture for IOT Network
现有问题 随着IOT中智能设备多样性和数目的增加,IOT的灵活性,效率,可用性,安全性和可扩展性的问题越来越明显. 实验目标 按照高适应性,可用性,容错性,性能,可靠性,可扩展性和安全性的设计原则,构 ...