- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我从原始输入到petgraph::UnGraph
结构都有一个解析器。我需要找到访问所有节点的最短路径。我找到了algo::dijkstra
,但是据我了解,Dijkstra只给了我连接两个特定节点的最短路径。
petgraph库中是否有一个函数可以轻松解决旅行商的问题,还是我需要自己实现一个求解器?我浏览了文档,但找不到任何东西,但这也许只是我有限的图形算法经验。
最佳答案
我和petgraph玩了一段时间,把你的问题当作挑战。
我发现petgraph非常强大,但是像许多复杂的系统一样,它很难理解,文档也没有提供足够的示例。
例如,EdgeReference
和EdgeIndex
之间的区别是什么?
如果我有一个EdgeReference
,如何获取EdgeIndex
?
如果有EdgeIndex
,我如何获得它连接的NodeIndex
?
无论如何,我使用petgraph作为起点创建了一个粗略的TSP解算器。请注意,它经过了最低限度的测试,不需要ni_to_n
,但是我保留了它,以防它对您有用,并且正在寻求许多改进。但是,它应该让您有所了解如何使用Ungraph<String, u32>
(节点是城市名称,边缘权重是u32距离)并获得近似的TSP解决方案。我的基本策略是使用petgraph的min_spanning_tree()
然后创建一个循环。以下的评论以了解更多。
希望这对您有所帮助,如果您对此有所改善,请发表!
use petgraph::algo::min_spanning_tree;
use petgraph::data::FromElements;
use petgraph::graph::{EdgeIndex, NodeIndex, UnGraph};
use std::collections::{HashMap, HashSet, VecDeque};
// function that returns the cycle length of the passed route
fn measure_route(route: &VecDeque<usize>, ddv: &[Vec<u32>]) -> u32 {
let mut len = 0;
for i in 1..route.len() {
len += ddv[route[i - 1]][route[i]];
}
len + ddv[route[0]][route[route.len() - 1]]
}
// Travelling salesman solver - the strategy is:
// 1) create a minimal spanning tree
// 2) reduce all nodes to two or fewer connections by deleting the most expensive connections
// 3) connect all nodes with 0 or 1 connections to each other via the least expensive connections
fn tsp(g: &UnGraph<String, u32>) -> u32 {
// translation collections: NodeIndex <-> usize
let n_to_ni: Vec<NodeIndex> = g.node_indices().collect();
let mut ni_to_n: HashMap<NodeIndex, usize> = HashMap::new();
for (n, ni) in g.node_indices().enumerate() {
ni_to_n.insert(ni, n);
}
// the original distance data in a vector
let mut ddv: Vec<Vec<u32>> = vec![vec![u32::MAX; g.node_count()]; g.node_count()];
for x in 0..g.node_count() {
ddv[x][x] = 0;
for y in x + 1..g.node_count() {
let mut edges = g.edges_connecting(n_to_ni[x], n_to_ni[y]);
let mut shortest_edge = u32::MAX;
while let Some(edge) = edges.next() {
if *edge.weight() < shortest_edge {
shortest_edge = *edge.weight();
}
}
ddv[x][y] = shortest_edge;
ddv[y][x] = shortest_edge;
}
}
// create a graph with only the needed edges to form a minimum spanning tree
let mut mst = UnGraph::<_, _>::from_elements(min_spanning_tree(&g));
// delete most expensive connections to reduce connections to 2 or fewer for each node
'rem_loop: loop {
for ni1 in mst.node_indices() {
let mut ev: Vec<(u32, EdgeIndex)> = vec![];
for ni2 in mst.node_indices() {
if let Some(ei) = mst.find_edge(ni1, ni2) {
ev.push((*mst.edge_weight(ei).unwrap(), ei));
}
}
if ev.len() > 2 {
ev.sort();
mst.remove_edge(ev[2].1);
// since we modified mst, need to start over as one other EdgeIndex will be invalid
continue 'rem_loop;
}
}
break;
}
// build a vector of routes from the nodes
let mut routes: Vec<VecDeque<usize>> = vec![];
let mut no_edges: Vec<usize> = vec![];
let mut visited: HashSet<usize> = HashSet::new();
let mut stack: VecDeque<usize> = VecDeque::default();
for n in 0..mst.node_count() {
if !visited.contains(&n) {
stack.push_back(n);
}
while !stack.is_empty() {
let n2 = stack.pop_front().unwrap();
let mut eflag = false;
visited.insert(n2);
for n3 in 0..mst.node_count() {
if mst.find_edge(n_to_ni[n2], n_to_ni[n3]).is_some() {
eflag = true;
if !visited.contains(&n3) {
stack.push_back(n3);
let mut fflag = false;
for r in routes.iter_mut() {
if r[0] == n2 {
r.push_front(n3);
fflag = true;
} else if r[r.len() - 1] == n2 {
r.push_back(n3);
fflag = true;
} else if r[0] == n3 {
r.push_front(n2);
fflag = true;
} else if r[r.len() - 1] == n3 {
r.push_back(n2);
fflag = true;
}
}
if !fflag {
// not found, create a new VecDeque
let mut vd = VecDeque::default();
vd.push_back(n2);
vd.push_back(n3);
routes.push(vd);
}
}
}
}
if !eflag {
no_edges.push(n2);
}
}
}
// put each node with no edges on the end of a route based on cost
for n in &no_edges {
let mut route_num = usize::MAX;
let mut insert_loc = 0;
let mut shortest = u32::MAX;
for ridx in 0..routes.len() {
if ddv[*n][routes[ridx][0]] < shortest {
shortest = ddv[*n][routes[ridx][0]];
route_num = ridx;
insert_loc = 0;
}
if ddv[routes[ridx][routes[ridx].len() - 1]][*n] < shortest {
shortest = ddv[routes[ridx][routes[ridx].len() - 1]][*n];
route_num = ridx;
insert_loc = routes[ridx].len() - 1;
}
}
if route_num == usize::MAX || shortest == u32::MAX {
panic!("unable to deal with singleton node {}", *n);
} else if insert_loc != 0 {
routes[route_num].push_back(*n);
} else {
routes[route_num].push_front(*n);
}
}
// merge routes into a single route based on cost - this could be improved by doing comparisons
// between routes[n] and routes[m] where m != 0 and n != 0
let mut tour = routes[0].clone();
for ridx in 1..routes.len() {
let mut v: Vec<(u32, bool, bool)> = vec![];
v.push((ddv[routes[ridx][routes[ridx].len() - 1]][tour[0]], true, false));
v.push((ddv[routes[ridx][routes[ridx].len() - 1]][tour[tour.len() - 1]], true, true));
v.push((ddv[routes[ridx][0]][tour[0]], false, false));
v.push((ddv[routes[ridx][0]][tour[tour.len() - 1]], false, true));
v.sort_unstable();
match v[0] {
(_, true, false) => {
// end to beginning of tour
for (insert_loc, n) in routes[ridx].iter().enumerate() {
tour.insert(insert_loc, *n);
}
}
(_, true, true) => {
// end to end of tour
let insert_loc = tour.len();
for n in &routes[ridx] {
tour.insert(insert_loc, *n);
}
}
(_, false, false) => {
// beginning to beginning of tour
for n in &routes[ridx] {
tour.push_front(*n);
}
}
(_, false, true) => {
// beginning to end of tour
for n in &routes[ridx] {
tour.push_back(*n);
}
}
}
}
// print out the tour and return its length
dbg!(tour.clone());
measure_route(&tour, &ddv)
}
关于graph - 如何使用 rust 和笔迹解决旅行商的问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60242573/
我正在制作一个应用程序,我在其中为每个国家/地区分配不同的值并根据该值执行某些操作。喜欢: Argentina 3 Australia 7 USA 23 要选择国家/地区,我需要使用用户当前所在的国家
这里是一般 Node mongodb 问题。 我有这个功能: static addSpaceToCreator = ( userId, spaceId, callback ) => {
Linux 中的 tcp 数据路径是否有很好的概述(2.6,如果路径实际不同则不是 2.4)?在 tcp/ip 堆栈处理的不同阶段,数据包在哪里? 数据包如何打包到tcp段,然后是ip数据包。它是如何
我是一名优秀的程序员,十分优秀!