Bootstrap

PAT甲级-1013 Battle Over Cities

题目

题目大意

给定一个城市图,如果攻陷一个城市,该城市连接的所有路都要被销毁。要求计算出连通剩余的城市最少需要修建几条路。该图有n个顶点,m条边,k个重点城市。分别求出每个重点城市被攻陷,连通剩余城市需要修建的路。

思路

求连通剩余城市需要修建的路,需要知道剩余城市的连通分量。连通分量可以看作一个连通的子图,单个顶点(没有任何边相连)也是一个连通分量。连通分量数 - 1 = 连通剩余图需要的最少边数。

所以关键就是求连通分量数,可以用dfs深度递归遍历来解决。从某一个顶点开始深度递归,直到递归不动,说明此时到达了该连通分量的终点。即每一次dfs都可以找到一个连通分量。为了避免重复递归,可以加一个bool数组,如果被递归过了就设为true,每次递归只遍历值为false的。而被攻陷的城市就可以看作已经被遍历过了,标记为true。

知识点

可变二维数组:vector<int> v[n]。

在C++中,数组作为函数参数传递时,默认传递的是数组的地址,因此不需要显式使用引用符号(&)。这不同于传递一个 vector 或其他类对象,这些通常按值传递,必须用引用符号 & 来避免复制。

代码

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

int n, m, k;
int g[1001][1001] = {0};

void dfs(int vi, bool b[]){  // 数组传入不用加引用,因为直接传入了地址
    b[vi] = true;
    for (int i = 1; i <= n; i++){
        if (g[vi][i] && !b[i]){
            dfs(i, b);
        }
    }
}  // 深度递归遍历,将遍历到的顶点设为访问过

int main(){
    cin >> n >> m >> k;
    for (int i = 0; i < m; i++){
        int v1, v2;
        cin >> v1 >> v2;
        g[v1][v2] = g[v2][v1] = 1;
    }  // 构建图

    for (int i = 0; i < k; i++){
        bool b[1001] = {false};  // 每个顶点是否被访问过;不要设为全局变量,否则每次循环还要手动进行初始化
        int vi;
        cin >> vi;
        b[vi] = true;  // 标记该顶点被访问过
        int cnt = 0;  // 剩余图的连通分量的个数
        for (int j = 1; j <= n; j++){
            if (!b[j]){
                dfs(j, b);  // 每次调用完相当于遍历完一个连通分量
                cnt++;
            }
        }
        cout << cnt - 1 << endl;  // 需要添加的边数 = 连通顶点数 - 1
    }

    return 0;
}

;