很抱歉,如果已经有人问这个问题,但我找不到与此特定问题相关的任何内容。我有一组已定义的节点,我想从中创建一个无向连接的图。我也有一组边连接这些节点,但我不能保证这些边的集合使图连接起来。我的情况的一个例子如下所示。
仔细检查会发现,根据我的边缘,节点集实际上是三个图。我想要做的是找到一种方法来确定我可以添加到我的边缘列表的边缘,以使其成为一个连接的图形。最好,我想添加尽可能少的边(即,我不想通过添加所有可能的边来解决问题)。为了增加伤害,我不想添加跨越其他边缘的边缘(每个节点都有一个定义的位置)。
答案 0 :(得分:3)
就像我在评论中说的那样,可以通过使用dfs遍历查找连接的组件,然后获取组件的端点并连接组件来完成,因此我们知道边缘将是最小的,即没有边缘=否对于组件-1,我使用邻接矩阵编写了一个c ++代码,除了一些实现细节之外,邻接列表解决方案是相同的。
#include<bits/stdc++.h>
using namespace std;
int n, m, G[100][100], vis[100], comp[100][100], sizeOfComp[100], noOfComp;
void dfs(int start){
vis[start] = 1;
comp[noOfComp][sizeOfComp[noOfComp]++] = start;
for(int i = 0;i < n;i++){
if(vis[i] == 1 || G[start][i] == 0) continue;
dfs(i);
}
}
int main(){
cin >> n >> m;
for(int i = 0;i < m;i++){
int p, q;cin >> p >> q;
G[p][q] = 1;G[q][p] = 1;
}
for(int i = 0;i < n;i++){
if(vis[i] == 0){
dfs(i);
noOfComp++;
}
}
cout << "New Edges : " << endl;
for(int i = 0;i < noOfComp-1;i++){
cout << comp[i][0] << " " << comp[i+1][0] << endl;
}
return 0;
}
指向Ideone上的解决方案:https://ideone.com/T0XKT3
答案 1 :(得分:3)
可以有效地找到连接的组件(例如,如u_seem_surprised所描述的)。这导致列出所有可能的连接链接。不幸的是,这个列表很长 - 任何一个组件中的任何节点都可以连接到任何其他节点,而且哪个组件最好连接也不明显。从这个长长的清单中找到符合您的非交叉要求的链接并不容易。
我怀疑这种混合问题没有任何已知的最佳算法。相反,我建议你尝试一些自然的启发式方法。
最好的启发式方法取决于问题的特征(例如,很少有组件和许多节点,反之亦然)。但这是我正在考虑的那种启发式的一个可能的例子。
要找到要连接任意两个连接组件的节点,我建议您首先尝试组件A中距离组件B中心最近的节点。我认为可以使用空间索引有效地完成。然后,您可以尝试将该节点连接到组件B中最近的节点,再次使用索引。
检查两个链接是否交叉的算法非常简单。
要决定连接哪些组件我认为你可以尝试这样的事情:
创建一个新图形,其中包含每个组件的质心的节点。将新网格添加到新图形,链接长度等于质心之间的距离。在这个新图上找到这些质心之间的最小生成树。现在,沿最小生成树连接组件。
但是,此算法可以告诉您连接无法连接的组件(例如,想象一个由三个同心组件组成的图形 - 您将无法将外部连接到内部)。所以这只是一个启发式的建议。
将组件连接到具有最近节点的另一个组件可能更好。