(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. redis集群在线迁移

    地址规划 主机名 ip地 端口 redis01 10.0.0.10 6379.6380 redis02 10.0.0.60 6379.6380 redis03 10.0.0.61 6379.6380 ...

  2. Java知识总结:Java反射机制(用实例理解)

    概念理解: 反射是指一类应用,它们能够自描述和自控制.也就是说,这类应用通过采用某种机制来 实现对自己行为的描述( self-representation )和检测( examination) ,并能 ...

  3. 使用Vue.js 和Chart.js制作绚丽多彩的图表

    前言 深入学习 chart.js 的选项来制作漂亮的图表.交互式图表可以给你的数据可视化提供很酷的展示方式.但是大多数开箱即用的解决方案用默认的选项并不能做出很绚丽的图表. 这篇文章中,我会教你如何自 ...

  4. vue配置config ‘./.../.../***/**.vue’路径别名

    cli-4的脚手架配置 因为组件的引用,经常会遇到import * from  '../../../components/common/***.vue‘这样的引入格式,太复杂了,所以可以在vue里面配 ...

  5. Dockfile的详解

    Dockerfile是构建镜像的指令文件,按照dockerfile的规范分为如下几部分: FROM 基础镜像,FROM alpine:3.8(任何的一个镜像都可以作为基础镜像,主要看我们做的镜像是干嘛 ...

  6. Vue - 引入本地图片的两种方式

    第一种,只引入单个图片,这种引入方法在异步中引入则会报错. 比如需要遍历出很多图片展示时 <image :src = require('图片的路径') /> 第二种,可引入多个图片,也可引 ...

  7. SpringBoot初试牛刀

    新建 Spring Boot 项目常用的两种方式 你可以通过 https://start.spring.io/ 这个网站来生成一个 Spring Boot 的项目. 你可以选择自己喜欢的依赖进行加载到 ...

  8. 前端学习笔记系列一:8 <noscript>…</noscript>,网站路径,vscode跳出右括号

    1.<noscript>…</noscript> 在body中使用此段代码,可识别 <script> 标签但无法支持其中的脚本的浏览器. 此段代码意思为如果浏览器不 ...

  9. Hibernate一对多(多对一)外键设置汇总

    我打算在角色表(role)中添加一个帐号表(account)的外键(accountId),步骤如下: 1.首先在角色表(role)中添加列. 添加语句:alter table role add(acc ...

  10. FTP 服务器在WIN10上的搭建及服务端下载文件实例

    1.搭建 (1)控制面板--->程序----->将FTP服务器打勾 (2)输入iis,或者右键桌面-->管理-->服务和应用程序--->internet informat ...