我正在尝试使用boost的prim算法来查找使用边缘权重和id号而不是边缘权重的最小生成树。
例如,如果两个边权重均为1,那么将比较一个id,无论哪个较小都会打破平局。
我创建了一个EdgeWeight类并重载了<和+运算符执行此操作,然后将edge_weight_t属性从int更改为EdgeWeight,希望它能够正常工作。
// TestPrim.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <boost/config.hpp>
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/prim_minimum_spanning_tree.hpp>
using namespace std;
class EdgeWeight{
public:
EdgeWeight(){}
EdgeWeight(int weightIn, int destinationIdIn){
weight = weightIn;
destinationId = destinationIdIn;
}
bool operator<(const EdgeWeight& rhs) const {
if (weight < rhs.weight)
return true;
else if(weight == rhs.weight){
if (destinationId < rhs.destinationId)
return true;
else
return false;
}
else
return false;
}
EdgeWeight operator+(const EdgeWeight& rhs) const {
EdgeWeight temp;
temp.weight = weight + rhs.weight;
temp.destinationId = destinationId + rhs.destinationId;
return temp;
}
int weight;
int destinationId;
};
int _tmain(int argc, _TCHAR* argv[])
{
using namespace boost;
typedef adjacency_list < vecS, vecS, undirectedS, property<vertex_distance_t, EdgeWeight>, property < edge_weight_t, EdgeWeight > > Graph;
typedef std::pair < int, int >E;
const int num_nodes = 5;
E edges[] = { E(0, 2), E(1, 3), E(1, 4), E(2, 1), E(2, 3),
E(3, 4), E(4, 0)
};
EdgeWeight weights[] = { EdgeWeight(1, 2), EdgeWeight(1, 3), EdgeWeight(2, 4),
EdgeWeight(7, 1), EdgeWeight(3, 3), EdgeWeight(1, 4), EdgeWeight(1, 0) };
Graph g(edges, edges + sizeof(edges) / sizeof(E), weights, num_nodes);
property_map<Graph, edge_weight_t>::type weightmap = get(edge_weight, g);
std::vector < graph_traits < Graph >::vertex_descriptor > p(num_vertices(g));
prim_minimum_spanning_tree(g, &p[0]);
for (std::size_t i = 0; i != p.size(); ++i)
if (p[i] != i)
std::cout << "parent[" << i << "] = " << p[i] << std::endl;
else
std::cout << "parent[" << i << "] = no parent" << std::endl;
return EXIT_SUCCESS;
}
我收到错误,“c:\ program files(x86)\ microsoft visual studio 10.0 \ vc \ include \ limits(92):错误C2440:'':无法从'int'转换为'D' 1 GT;没有构造函数可以采用源类型,或者构造函数重载决策是不明确的“
我这样做是对的吗?有更好的方法吗?
http://www.boost.org/doc/libs/1_38_0/libs/graph/doc/prim_minimum_spanning_tree.html http://www.boost.org/doc/libs/1_38_0/boost/graph/prim_minimum_spanning_tree.hpp
编辑:好吧所以我现在使用cjm的扰动方法实现了权重,但是在将来我相信我将不得不以某种方式使用上述方法,仍然想知道如何做到这一点
edit2:基于Jeremiah的反应,我将vertex_distance_t从int更改为EdgeWeight但得到了相同的错误
答案 0 :(得分:2)
顶点距离图的value_type
需要与算法的边缘权重类型相同。文档暗示(在distance_map
的描述的第一部分中)但没有明确说明。我(自回答这个问题以来)澄清并纠正了Boost主干中的文档。
答案 1 :(得分:2)
Boost实施的“Prim”算法(Jarník在Prim之前差不多三十年发现了算法)使用Dijkstra算法的通用实现作为子程序。我确定有人认为这是非常聪明。
Dijkstra算法需要非负权重,支持添加身份和比较,这些操作必须兼容(对于所有x,y,z,如果x <= y,则x + z <= y + z) 。在实践中,实例化这些操作的唯一有用的方法是习惯性的(我把它拿回来;它可能以同样的方式打破Dijkstra的算法),因此Boost的Dijkstra算法的实现明智地假设存在“无限”(std::numeric_limits<vertex_distance_t>::max()
)。它还声称所有权重都是非负的。
相比之下,Prim的算法需要仅支持比较的权重。你可能想知道“最小生成树”中的“最小”是什么意思没有加法,但是最小生成树的另一种表征是,对于从顶点u到顶点v的每条路径P,P中最长的边是至少与从u到v的树路径中最长的边缘一样长。
结果是Boost对Prim算法的实现做出了一些无根据的假设。您可以按照以下方式对它们进行编码,但Boost似乎没有合同义务在将来不破坏此黑客攻击。
摆脱加法运算符;它没有被使用。
由于Boost将声明所有权重都不小于默认构造的值,所以让我们设置默认的“负无穷大”。
#include <limits>
...
EdgeWeight() : weight(numeric_limits<int>::min()),
destinationId(numeric_limits<int>::min()) {}
提升需要“正无限”,因此我们需要专注std::numeric_limits
。
namespace std {
template<>
struct numeric_limits<EdgeWeight> {
static EdgeWeight max() { return EdgeWeight(numeric_limits<int>::max(),
numeric_limits<int>::max()); }
};
}
您可以简化比较。
bool operator<(const EdgeWeight& rhs) const {
return (weight < rhs.weight ||
(weight == rhs.weight && destinationId < rhs.destinationId));
}