C++ Karger的算法不适用于单次运行,而适用于多次运行
我正在尝试实现Karger的算法来寻找am无向图中的最小割。我使用的图形有8条边,如t2 2D向量所示 为此,我使用了2D向量和图的邻接列表实现 对于选择随机边,我实际上随机选择了一个顶点,然后从其边列表中随机选择另一个顶点来选择随机边 然而,即使我相信我正确地遵循了所有的步骤,该算法似乎并没有为一次运行给出正确的答案,并且在多次运行中出现故障 我的代码如下:C++ Karger的算法不适用于单次运行,而适用于多次运行,c++,algorithm,c++11,random,graph,C++,Algorithm,C++11,Random,Graph,我正在尝试实现Karger的算法来寻找am无向图中的最小割。我使用的图形有8条边,如t2 2D向量所示 为此,我使用了2D向量和图的邻接列表实现 对于选择随机边,我实际上随机选择了一个顶点,然后从其边列表中随机选择另一个顶点来选择随机边 然而,即使我相信我正确地遵循了所有的步骤,该算法似乎并没有为一次运行给出正确的答案,并且在多次运行中出现故障 我的代码如下: #include <iostream> #include <vector> #include <fstre
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include <random>
#include <algorithm>
#include <ctime>
#define MAX_ELEMENTS 201
using namespace std;
typedef int64_t int64;
//RNG Stuff
random_device rd;
mt19937_64 rng(rd());
uniform_int_distribution<int> uni(1, 9);
vector< vector<int64> > t(MAX_ELEMENTS);
vector < vector<int>> t2(9);
int mincut = 0;
void printVector(){
for (auto j : t2) {
for (auto l : j)
cout << l << " ";
cout << endl << "Hahaha " << j.size() << endl;
}
}
int randomNum() {
return uni(rng);
}
int KargersAlgorithm(void) {
int minOfTwo;
t2 = {{}, {1 ,2 ,3 ,4 ,7},
{2, 1 ,3 ,4},
{3, 1, 2, 4},
{4, 1, 2, 3, 5},
{5, 4, 6 ,7 ,8},
{6, 5, 7, 8},
{7, 1 ,5 ,6, 8},
{8, 5, 6, 7}};
while (t2.size() > 3) {
/*
* Randomly select vertices
*/
int nodeStart = 0;
while(nodeStart == 0)
nodeStart = randomNum() % t2.size();
int nodeEnd = 0;
while(nodeEnd == 0)
nodeEnd = randomNum() % t2[nodeStart].size();
//Insert all the edges from nodeEnd to nodeStart aka merge the vertices
t2[nodeStart].insert(t2[nodeStart].end(), t2[nodeEnd].begin(), t2[nodeEnd].end());
//Node renaming
for (int i = 1; i < t2[nodeEnd].size(); i++) { //For each vertex in nodeEnd
int foundEdge = t2[nodeEnd][i]; //Found an edge from nodeEnd to foundEdge,, so need to rename all the nodeEnd to nodeStart in this list
// cout<< "i: " << i << " FoundEdge: " << foundEdge << endl;
replace(t2[foundEdge].begin(), t2[foundEdge].end(), t2[nodeEnd][0], t2[nodeStart][0]); //Replace all the nodeEnd with t2[nodeStart][0] since that gives the ID number
}
//Remove self-loops from nodeStart
t2[nodeStart].erase(std::remove(t2[nodeStart].begin() + 1, t2[nodeStart].end(), t2[nodeStart][0]),
t2[nodeStart].end());
//Kill nodeEnd :(
t2.erase(t2.begin() + nodeEnd);
}
//printVector();
return min(t[1].size(), t[2].size());
}
int main(){
int min = 0;
for(int i =0; i < 1000000; i++) {
t2.clear();
int x = KargersAlgorithm();
if(x < min)min = x;
}
cout << min;
return 0;
}
由于第一个元素表示顶点编号,显然顶点4和5最后被保留
那么,以下是我的疑问:
在这个实现中,有没有更好的方法来随机选择顶点?现在,由于t[0]在从1到8的索引中没有任何内容,因此对t[0]的任何访问都会使程序崩溃
我得到的输出正确吗?我觉得应该是这样的
45555
544
但可能是我不太明白
我应该得到的实际切碎值是多少?我怎样才能从输出中推断出来呢?现在我想这是两种尺码中最小的一种,但它似乎是非常错误的
每当我多次尝试运行该程序时,它就会崩溃。以下是相同代码的ideone链接:
我知道我的理解可能不完整,但到目前为止,在我在web上看到的其他地方,要么我无法理解代码,要么这些地方没有使用我的实现
任何帮助都将不胜感激。谢谢大家!
编辑1:根据samgak和Patryk Obara的建议。我在每个函数调用的开头添加了一个clear,并将t2数组大小的declr扩展到9,尽管这可能没什么大不了的,但即使这样,它也会崩溃。根据CLion的说法,在第29次迭代中,由于foundEdge中的垃圾负值,它在代码中的替换行96处崩溃,即使地址看起来是合法的。所以我还是很困惑。。。提前谢谢 我的建议是通过调试器运行它,看看它在哪里崩溃,然后从那里开始。第一个崩溃是line,在这里填充t2,将9个元素放入一个大小为8的向量中。第二次崩溃发生在直线上,即合并顶点的位置。不幸的是,我现在没有时间阅读您的实现并跟进。在KargersAlgorithm函数开始时调用clear on your vectors我添加了您的两个建议,并使用调试器检查了它何时何地崩溃。谢谢你的建议!还有一点意见:连接两个向量并不是合并两个顶点的最佳方法。毕竟,您希望删除重复的顶点,这似乎是您的算法中缺少的-您可能希望对邻接列表使用std::set-合并两个集合将自动删除重复的顶点。嗯,我明白了。但是,在删除重复项的同时合并它们不会删除存在的任何平行边吗?我的建议是通过调试器运行此操作,查看它在哪里崩溃,然后从那里开始。第一个崩溃是line,在这里填充t2,将9个元素放入一个大小为8的向量中。第二次崩溃发生在直线上,即合并顶点的位置。不幸的是,我现在没有时间阅读您的实现并跟进。在KargersAlgorithm函数开始时调用clear on your vectors我添加了您的两个建议,并使用调试器检查了它何时何地崩溃。谢谢你的建议!还有一点意见:连接两个向量并不是合并两个顶点的最佳方法。毕竟,您希望删除重复的顶点,这似乎是您的算法中缺少的-您可能希望对邻接列表使用std::set-合并两个集合将自动删除重复的顶点。嗯,我明白了。但是,在删除重复项时合并它们不会删除存在的任何平行边吗?
4 2 3 5 2 3 7
5 4 6 7 8 7 4 6 8 8 6