(This problem is the same as *Minimize Malware Spread*, with the differences bolded.)

In a network of nodes, each node i is directly connected to another node j if and only if graph[i][j] = 1.

Some nodes initial are initially infected by malware.  Whenever two nodes are directly connected and at least one of those two nodes is infected by malware, both nodes will be infected by malware.  This spread of malware will continue until no more nodes can be infected in this manner.

Suppose M(initial) is the final number of nodes infected with malware in the entire network, after the spread of malware stops.

We will remove one node from the initial list, completely removing it and any connections from this node to any other node.  Return the node that if removed, would minimize M(initial).  If multiple nodes could be removed to minimize M(initial), return such a node with the smallest index.

Example 1:

Input: graph = [[1,1,0],[1,1,0],[0,0,1]], initial = [0,1]
Output: 0

Example 2:

Input: graph = [[1,1,0],[1,1,1],[0,1,1]], initial = [0,1]
Output: 1

Example 3:

Input: graph = [[1,1,0,0],[1,1,1,0],[0,1,1,1],[0,0,1,1]], initial = [0,1]
Output: 1

Note:

  1. 1 < graph.length = graph[0].length <= 300
  2. 0 <= graph[i][j] == graph[j][i] <= 1
  3. graph[i][i] = 1
  4. 1 <= initial.length < graph.length
  5. 0 <= initial[i] < graph.length

这道题是之前那道 [Minimize Malware Spread](https://www.cnblogs.com/grandyang/p/11838844.html) 的拓展,实际上只是修改了一个地方,就是文中加粗的地方,说的是每次直接将这个结点去掉,而不是像之前的题目那样只是将其不当做感染源。那么二者到底有什么区别呢,实际上并不是在所有的 test case 上都有区别,只是部分会有。比如对于 graph=[[1,1,0],[1,1,1],[0,1,1]], initial=[0,1] 来说,可以发现结点的链接情况是 0-1-2,感染源结点是0和1,若是按之前题目的要求,移除0和1都不会减少最终感染个数,但是应该返回结点0,因为其 index 小。但是应用此题的条件,就一定要返回结点1,因为移除结点1之后,就断开了结点0和结点2的连接,最终只有病毒源结点0会保持感染状态,这就是二者的区别所在。解题思路完全可以在之前那道题 [Minimize Malware Spread](https://www.cnblogs.com/grandyang/p/11838844.html) 的基础上进行修改,最简单暴力的修改其实是新建一个 graph 的副本,然后当要删掉某个结点i的时候,将所有的 graph[i][:] 和 graph[:][i] 都赋值为0即可,这样修改邻接矩阵就相当于断开了结点i和其他所有结点之间的连接,博主亲测解法1和解法2都可以用此方法通过。当然也可以用其他的方法,这里博主将要删除的结点 num 带入到了子函数中,在 BFS 中遍历某个结点的所有邻接点的时候,只要多加个判断,跳过 num 结点也是可以的,参见代码如下:


解法一:

class Solution {
public:
int minMalwareSpread(vector<vector<int>>& graph, vector<int>& initial) {
int mn = INT_MAX, res = 0;
unordered_set<int> infected(initial.begin(), initial.end());
for (int num : initial) {
infected.erase(num);
int cnt = helper(graph, infected, num);
if (cnt < mn || (cnt == mn && num < res)) {
mn = cnt;
res = num;
}
infected.insert(num);
}
return res;
}
int helper(vector<vector<int>>& graph, unordered_set<int> infected, int num) {
queue<int> q;
for (int num : infected) q.push(num);
while (!q.empty()) {
auto t = q.front(); q.pop();
for (int i = 0; i < graph[t].size(); ++i) {
if (i == num || graph[t][i] != 1 || infected.count(i)) continue;
infected.insert(i);
q.push(i);
}
}
return infected.size();
}
};

当然对于 DFS 的解法也可以做类似的处理,除了上面提到的建立 graph 副本并修改的方法之外,也可以用其他的方法。这里博主对于每个要移除的结点 num,先将其加入 visited 之中,然后在遍历的时候,只对非 num 结点调用递归函数,可以得到同样的结果,参见代码如下:


解法二:

class Solution {
public:
int minMalwareSpread(vector<vector<int>>& graph, vector<int>& initial) {
int mn = INT_MAX, res = 0;
unordered_set<int> infected(initial.begin(), initial.end());
for (int num : initial) {
infected.erase(num);
int cnt = 0;
unordered_set<int> visited{{num}};
for (int cur : infected) {
if (cur != num) helper(graph, cur, visited, cnt);
}
if (cnt < mn || (cnt == mn && num < res)) {
mn = cnt;
res = num;
}
infected.insert(num);
}
return res;
}
void helper(vector<vector<int>>& graph, int cur, unordered_set<int>& visited, int& cnt) {
if (visited.count(cur)) return;
visited.insert(cur);
++cnt;
for (int i = 0; i < graph[cur].size(); ++i) {
if (graph[cur][i] != 1) continue;
helper(graph, i, visited, cnt);
}
}
};

讨论:博主本想将之前那道 [Minimize Malware Spread](https://www.cnblogs.com/grandyang/p/11838844.html) 的解法三也修改一下用到这里,但发现比较难修改,论坛虽然也有一些使用联合查找 Union Find 来做的解法,但是感觉都比较复杂,这里就不写了,若哪位看官大神可以将之前的解法三移植过来,请务必留言告诉博主哈~


Github 同步地址:

https://github.com/grandyang/leetcode/issues/928

类似题目:

Minimize Malware Spread

参考资料:

https://leetcode.com/problems/minimize-malware-spread-ii/

https://leetcode.com/problems/minimize-malware-spread-ii/discuss/217529/c%2B%2B-solution-bfs

https://leetcode.com/problems/minimize-malware-spread-ii/discuss/184645/Straightforward-DFS-Java-6-ms

[LeetCode All in One 题目讲解汇总(持续更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)

[LeetCode] 928. Minimize Malware Spread II 最大程度上减少恶意软件的传播之二的更多相关文章

  1. [LeetCode] 924. Minimize Malware Spread 最大程度上减少恶意软件的传播

    In a network of nodes, each node i is directly connected to another node j if and only if graph[i][j ...

  2. [Swift]LeetCode928. 尽量减少恶意软件的传播 II | Minimize Malware Spread II

    (This problem is the same as Minimize Malware Spread, with the differences bolded.) In a network of ...

  3. 【leetcode】924.Minimize Malware Spread

    题目如下: In a network of nodes, each node i is directly connected to another node j if and only if grap ...

  4. [Swift]LeetCode924.尽量减少恶意软件的传播 | Minimize Malware Spread

    In a network of nodes, each node i is directly connected to another node j if and only if graph[i][j ...

  5. LeetCode刷题总结-数组篇(上)

    数组是算法中最常用的一种数据结构,也是面试中最常考的考点.在LeetCode题库中,标记为数组类型的习题到目前为止,已累计到了202题.然而,这202道习题并不是每道题只标记为数组一个考点,大部分习题 ...

  6. 【LeetCode】227. Basic Calculator II 解题报告(Python)

    [LeetCode]227. Basic Calculator II 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博客: h ...

  7. 乘风破浪:LeetCode真题_040_Combination Sum II

    乘风破浪:LeetCode真题_040_Combination Sum II 一.前言 这次和上次的区别是元素不能重复使用了,这也简单,每一次去掉使用过的元素即可. 二.Combination Sum ...

  8. [leetcode]Unique Binary Search Trees II @ Python

    原题地址:https://oj.leetcode.com/problems/unique-binary-search-trees-ii/ 题意:接上一题,这题要求返回的是所有符合条件的二叉查找树,而上 ...

  9. LeetCode 445——两数相加 II

    1. 题目 2. 解答 2.1 方法一 在 LeetCode 206--反转链表 和 LeetCode 2--两数相加 的基础上,先对两个链表进行反转,然后求出和后再进行反转即可. /** * Def ...

随机推荐

  1. Day11 - J - Brave Game HDU - 1846

    十年前读大学的时候,中国每年都要从国外引进一些电影大片,其中有一部电影就叫<勇敢者的游戏>(英文名称:Zathura),一直到现在,我依然对于电影中的部分电脑特技印象深刻.今天,大家选择上 ...

  2. Codeforces1303D. Fill The Bag

    1e18对应2进制有58位,可以直接暴力模拟,因为读入的数都是2次幂,__builtin_ctz这个内置gcc函数可以算出二进制下末尾有几个0,读入时统计,然后从n的最低位开始判断,注意每次升位的时候 ...

  3. Django 学习之From组件

    一.Form组件介绍 Form组件可以做的几件事情: 1.用户请求数据验证 2.自动生成错误信息 3.打包用户提交的正确信息 4.如果其中有一个错误了,其他的正确这,保留上次输入的内容 4.自动创建i ...

  4. 144、Java链表之定义一个Node类并输出

    01.代码如下: package TIANPAN; class Node { // 每一个链表实际上就是由多个节点组成的 private String data; // 要保存的数据 private ...

  5. Python 中的经典类新式类

    Python 中的经典类新式类 要知道经典类和新式类的区别,首先要掌握类的继承 类的继承的一个优点就是减少代码冗余 广度优先和深度优先,这主要是在多类继承的时候会使用到 经典类和新式类的主要区别就是类 ...

  6. 标准模板库中的栈(stack)

    ////C++数据结构与算法(第4版) Adam Drozdek 著  徐丹  吴伟敏<<清华大学出版社>> STL中的通用栈类实现为容器适配器:使用以指定方式运行的容器.栈容 ...

  7. 一、Servlet之14道面试题

    1.什么是Servlet    Servlet是用Java编写的服务端程序,它与协议和平台无关,运行于支持Java的应用服务器中,Java Servlet可以动态的扩展服务器的能力,并采用请求-响应模 ...

  8. robotframework+appium 实现App自动化值环境搭建(一)

    第一步: Cmd命令输入pip install robotframework-appiumlibrary  下载和导入appiumlibrary 第二步: 安装JDK,附件有JDK1.8安装包 第三步 ...

  9. 如何书写高效的MySQL查询?

    How to write efficient MySQL query statements WHERE子句中的书写注意事项 模糊查询(like)时需要注意的事项 索引 字段类型 表连接时的注意事项 其 ...

  10. 「BJWC2012」冻结

    传送门 Luogu 解题思路 分层图最短路,层与层之间的边的边权减半,然后就是板子了. 细节注意事项 咕咕咕. 参考代码 #include <algorithm> #include < ...