使用广度优先搜索实现供水问题

data structurec++programming

在这个问题中,我们将找到最多可以供水的城市数量。

我们可以将这个问题看作是一个遍历阻塞节点的图。因此,我们可以使用广度优先搜索算法来找到最大连通城市数量。

问题描述

我们给出了总共N个城市。此外,我们还给出了两个城市之间的一条边;所有城市都与其他一个或多个城市相连。我们需要在每个城市建立供水连接。我们还给出了一个blocked[]数组,其中包含0和1。值1表示该城市被阻塞。因此,我们无法将水输送到该城市。值0表示我们可以将水输送到该城市。我们需要找出最多可以供水的城市数量。

示例

输入

cities = 5; roads = 1-> 2, 2 -> 3, 3-> 4, 4-> 5; blocked[] = {0, 1, 0, 0, 1};

输出

4

解释

如果我们从第 3 个或第 4 个城市开始供水,我们可以向第 2、3、4 和第 5 个城市供水。

输入

cities = 5; roads = 1->2, 2->3, 3->4, 4->5; blocked[] = {1, 1, 1, 1, 1};

输出

1

解释

当所有城市都阻塞后,我们可以向任何连接到供水管道的城市供水。

输入

cities = 6; roads = 1-> 2, 2 -> 3, 2 -> 6, 3-> 4, 4-> 5; blocked[] = {1, 0, 0, 1, 0, 1};

输出

4

解释

我们可以将供水管道连接到第二个城市,从而为第一、第二、第三和第四个城市供水。

方法

在此方法中,我们将使用广度优先搜索算法找到所有连通城市的集合。之后,我们可以将连通最多城市的最大值作为答案。

算法

  • 步骤 1 - 使用 false 布尔值初始化 visitor[] 数组,以便在广度优先搜索遍历时跟踪该城市是否被访问过。

  • 步骤 2 - 将 maxi 初始化为 1,以跟踪连通城市的数量。

  • 步骤 3 - 使用循环遍历每个城市。如果该城市未被封锁且之前未被访问过,则调用 findConnectedCities() 函数查找与当前城市相连的所有城市。

  • 步骤 3.1 − 在 findConnectedCities() 函数中,将当前城市标记为已访问。

  • 步骤 3.2 − 定义队列并将源城市插入队列。另外,将 'cnt' 初始化为 0,以存储已连接城市的数量。

  • 步骤 3.3 - 遍历队列(当队列不为空时)。

  • 步骤 3.3.1 - 弹出队列的第一个元素。

  • 步骤 3.3.2 - 遍历当前城市的所有相邻城市。

  • 步骤 3.3.3 - 如果该城市未被访问或未被阻塞,则将 'cnt' 加 1,将其标记为已访问,然后将其插入队列。

  • 步骤 3.3.4 - 如果该城市未被访问且被阻塞,则将 'cnt' 加 1。

  • 步骤 3.3.5 -从队列中弹出城市。

  • 步骤 3.4 - 返回 cnt + 1。此处,我们将源城市本身的数量加 1。

  • 步骤 4 - 如果函数返回的值大于最大值,则使用新值更新最大值。

  • 步骤 5 - 返回最大值。

示例

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

int findConnectedCities(int blocked[], bool visited[], vector<int> roads[], int source) {
   visited[source] = true;
   queue<int> que;
   que.push(source);
   int cnt = 0;
   while (!que.empty()) {
      int temp = que.front();
      for (int p = 0; p < roads[temp].size(); p++) {
         // 当邻近城市没有被封锁和访问时
         if (!visited[roads[temp][p]] && blocked[roads[temp][p]] == 0) {
            cnt++;
            visited[roads[temp][p]] = true;
            que.push(roads[temp][p]);
         }
         // 我们可以给被封锁的城市供水,但被封锁的城市却无法给其他城市供水
         else if (!visited[roads[temp][p]] && blocked[roads[temp][p]] == 1) {
            cnt++;
         }
      }
      que.pop();
   }
   return cnt + 1;
}
int maxNumberCities(int cities, int blocked[], vector<int> roads[]) {
   bool visited[cities + 1];
   int maxi = 1;
   for (int p = 1; p <= cities; p++)
      visited[p] = false;
   // 为每个城市启动 BFS
   for (int p = 1; p <= cities; p++) {
      // 当城市没有被封锁,没有被访问时
      if (blocked[p] == 0 && !visited[p]) {
         int temp = findConnectedCities(blocked, visited, roads, p);
         if (temp > maxi) {
            maxi = temp;
         }
      }
   }
   return maxi;
}
int main() {
    int city = 5;
    vector roads[cities + 1];
    // 存储道路连接
    roads[1].push_back(2);
    roads[2].push_back(1);
    roads[2].push_back(3);
    roads[3].push_back(2);
    roads[3].push_back(4);
    roads[4].push_back(3);
    roads[3].push_back(5);
    roads[5].push_back(3);
    // 存储城市是否被封锁
    int blocked[] = {0, 1, 0, 0, 1};
    cout << "我们最多可以供水的城市数量为 " << maxNumberCities(cities, blocked, roads);
    return 0;
}

输出

我们最多可以供水的城市数量为 4 个
  • 时间复杂度 - O(N) 遍历所有城市。

  • 空间复杂度 - O(N) 将城市存储在队列中。

结论

给定的问题与寻找最大岛屿的大小非常相似。在岛屿问题中,我们同样从未访问的节点开始广度优先遍历,并找到连通的节点。


相关文章