📅  最后修改于: 2023-12-03 15:39:09.976000             🧑  作者: Mango
在一个无向图中,定义一对节点之间的路径为路径起点和路径终点之间的所有节点,如果这条路径经过的节点中恰好有两个节点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;
}
}
}
}
}
于是,我们就完成了这个问题的求解。