📌  相关文章
📜  对的数量,以使对之间的路径具有两个顶点A和B(1)

📅  最后修改于: 2023-12-03 15:39:09.976000             🧑  作者: Mango

寻找对的数量,使对之间的路径具有两个顶点A和B

问题描述

在一个无向图中,定义一对节点之间的路径为路径起点和路径终点之间的所有节点,如果这条路径经过的节点中恰好有两个节点A和B,那么这条路径就符合要求。现在你需要编写一个程序,根据给定的无向图,求出符合要求的对的数量。

解法分析
暴力枚举

我们可以枚举每一对节点作为A和B,然后对于每一次枚举,都深度优先搜索一次,看能否找到一条路径恰好经过这两个节点。这种做法时间复杂度是$O(n^3)$, 显然会超时。

先找出每个节点的邻居

我们可以先对于每一个节点,找出它的邻居节点,然后对于每一个邻居节点,再找出它的邻居节点,以此类推,直到找出所有节点的邻居节点。然后,我们再枚举每一对节点作为A和B,看它们之间是否存在一个中间节点,使得A和B都是这个节点的邻居。这种做法的时间复杂度是$O(n^2)$。

具体实现过程中,我们可以使用邻接表来存储图的结构,邻接表可以用一个vector数组来实现,数组的下标表示节点编号,数组的值是一个vector,表示这个节点的邻居节点。

vector<int> adj[N];
for (int i = 0; i < m; ++i) {
    int u, v;
    cin >> u >> v;
    adj[u].push_back(v);
    adj[v].push_back(u);
}

然后我们用DFS遍历图,找出每个节点的邻居节点。如下是代码实现。

int vis[N];
vector<int> neighbor[N];

void dfs(int u, int fa) {
    vis[u] = 1;
    for (int i = 0; i < adj[u].size(); ++i) {
        int v = adj[u][i];
        if (v == fa || vis[v]) continue;
        neighbor[u].push_back(v);
        dfs(v, u);
    }
}

接下来,我们再枚举每一对节点作为A和B,看它们之间是否存在一个中间节点,使得A和B都是这个节点的邻居。

int cnt = 0;
for (int i = 1; i <= n; ++i) {
    for (int j = i + 1; j <= n; ++j) {
        if (i == j) continue;
        for (int k = 0; k < neighbor[i].size(); ++k) {
            int v = neighbor[i][k];
            if (v == j) {
                ++cnt;
                break;
            }
            for (int t = 0; t < neighbor[j].size(); ++t) {
                int u = neighbor[j][t];
                if (u == i) continue;
                if (u == v) {
                    ++cnt;
                    break;
                }
            }
        }
    }
}

于是,我们就完成了这个问题的求解。

返回结果

以下是完整代码的markdown格式:

# 寻找对的数量,使对之间的路径具有两个顶点A和B

## 问题描述

在一个无向图中,定义一对节点之间的路径为路径起点和路径终点之间的所有节点,如果这条路径经过的节点中恰好有两个节点A和B,那么这条路径就符合要求。现在你需要编写一个程序,根据给定的无向图,求出符合要求的对的数量。

## 解法分析

### 暴力枚举

我们可以枚举每一对节点作为A和B,然后对于每一次枚举,都深度优先搜索一次,看能否找到一条路径恰好经过这两个节点。这种做法时间复杂度是$O(n^3)$, 显然会超时。

### 先找出每个节点的邻居

我们可以先对于每一个节点,找出它的邻居节点,然后对于每一个邻居节点,再找出它的邻居节点,以此类推,直到找出所有节点的邻居节点。然后,我们再枚举每一对节点作为A和B,看它们之间是否存在一个中间节点,使得A和B都是这个节点的邻居。这种做法的时间复杂度是$O(n^2)$。

具体实现过程中,我们可以使用邻接表来存储图的结构,邻接表可以用一个vector数组来实现,数组的下标表示节点编号,数组的值是一个vector,表示这个节点的邻居节点。

```cpp
vector<int> adj[N];
for (int i = 0; i < m; ++i) {
    int u, v;
    cin >> u >> v;
    adj[u].push_back(v);
    adj[v].push_back(u);
}

然后我们用DFS遍历图,找出每个节点的邻居节点。如下是代码实现。

int vis[N];
vector<int> neighbor[N];

void dfs(int u, int fa) {
    vis[u] = 1;
    for (int i = 0; i < adj[u].size(); ++i) {
        int v = adj[u][i];
        if (v == fa || vis[v]) continue;
        neighbor[u].push_back(v);
        dfs(v, u);
    }
}

接下来,我们再枚举每一对节点作为A和B,看它们之间是否存在一个中间节点,使得A和B都是这个节点的邻居。

int cnt = 0;
for (int i = 1; i <= n; ++i) {
    for (int j = i + 1; j <= n; ++j) {
        if (i == j) continue;
        for (int k = 0; k < neighbor[i].size(); ++k) {
            int v = neighbor[i][k];
            if (v == j) {
                ++cnt;
                break;
            }
            for (int t = 0; t < neighbor[j].size(); ++t) {
                int u = neighbor[j][t];
                if (u == i) continue;
                if (u == v) {
                    ++cnt;
                    break;
                }
            }
        }
    }
}

于是,我们就完成了这个问题的求解。