如何使用rust和petgraph解决旅行推销员问题?

如何使用rust和petgraph解决旅行推销员问题?,graph,rust,petgraph,Graph,Rust,Petgraph,我有一个从原始输入到petgraph::UnGraph结构的解析器。我需要找到访问所有节点的最短路径。我找到了algo::dijkstra,但据我所知,dijkstra只会给出连接两个特定节点的最短路径 petgraph库中是否有一个函数提供了一种轻松解决旅行推销员问题的方法,或者我需要自己实现一个解算器?我浏览了文档,但找不到任何内容,但可能这只是我在图形算法方面的有限经验。我已经玩了一段时间petgraph,并将您的问题视为一个挑战。 我发现petgraph非常强大,但与许多复杂系统一样,它

我有一个从原始输入到
petgraph::UnGraph
结构的解析器。我需要找到访问所有节点的最短路径。我找到了
algo::dijkstra
,但据我所知,dijkstra只会给出连接两个特定节点的最短路径


petgraph库中是否有一个函数提供了一种轻松解决旅行推销员问题的方法,或者我需要自己实现一个解算器?我浏览了文档,但找不到任何内容,但可能这只是我在图形算法方面的有限经验。

我已经玩了一段时间petgraph,并将您的问题视为一个挑战。 我发现petgraph非常强大,但与许多复杂系统一样,它很难理解,文档中也没有给出足够的示例。
例如,
EdgeReference
EdgeIndex
之间有什么区别?
如果我有一个
EdgeReference
如何获得
EdgeIndex

如果有一个
EdgeIndex
如何获取它连接的
NodeIndex
s?
无论如何,我创建了一个粗糙的TSP解算器,使用petgraph作为起点。请注意,它是经过最低限度测试的,
ni_to_n
是不必要的,但我留下它是为了防止它对您有用,许多改进迫切需要改进。但是,它应该会让您了解如何使用
Ungraph
(节点是城市名称,边权重是u32距离)并获得近似的TSP解决方案。
我的基本策略是使用petgraph的
min_生成树()
,然后创建一个循环。
有关更多信息,请参阅下面的注释

我希望这是有用的,如果你改进它,请张贴

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)
}
使用petgraph::algo::min_生成树;
使用petgraph::data::FromElements;
使用petgraph::graph:{EdgeIndex,NodeIndex,UnGraph};
使用std::collections::{HashMap,HashSet,VecDeque};
//函数,该函数返回已传递路线的周期长度
fn测量路径(路径:&VecDeque,ddv:&Vec])->u32{
设mut len=0;
对于1..route.len()中的i{
len+=ddv[路线[i-1]][路线[i]];
}
len+ddv[路由[0][路由[route.len()-1]]
}
//旅行推销员解决方案-策略是:
//1)创建最小生成树
//2)通过删除最昂贵的连接,将所有节点减少到两个或更少的连接
//3)通过最便宜的连接将具有0或1个连接的所有节点相互连接
fn tsp(g:&UnGraph)->u32{
//翻译集:NodeIndex usize
设n_to_ni:Vec=g.node_index().collect();
让mut ni_to_n:HashMap=HashMap::new();
对于g.node_index()中的(n,ni)枚举()函数{
插入(ni,n);
}
//向量中的原始距离数据
让mut-ddv:Vec=Vec![Vec![u32::MAX;g.node_count()];g.node_count()];
对于0..g.节点计数()中的x{
ddv[x][x]=0;
对于x+1..g.节点计数()中的y{
设mut-edges=g.edges_连接(n_到_-ni[x],n_到_-ni[y]);
设mut最短边=u32::MAX;
而让一些(边)=边。下一个(){
if*edge.weight()<最短边{
最短_边=*edge.weight();
}
}
ddv[x][y]=最短_边;
ddv[y][x]=最短_边;
}
}
//创建一个只包含所需边的图,以形成最小生成树
设mut mst=UnGraph:::from_元素(最小生成树(&g));
//删除最昂贵的连接,以将每个节点的连接减少到2个或更少
“rem_循环:循环{
对于mst.node_索引()中的ni1{
让mut-ev:Vec=Vec![];
对于mst.node_索引()中的ni2{
如果让一些(ei)=mst.查找_边(ni1,ni2){
电动推力(*mst.边缘重量(ei).展开(),ei));
}
}
如果ev.len()大于2{
ev.sort();
mst.去除_边(ev[2].1);
//因为我们修改了mst,所以需要重新开始,因为另一个EdgeIndex将无效
继续“rem_循环”;
}
}
打破
}
//从节点构建路由向量
让mut路由:Vec=Vec![];
让mut无边:Vec=Vec![];
让mut访问:HashSet=HashSet::new();
让mut堆栈:VecDeque=VecDeque::default();
对于0..mst.node_count()中的n{
如果!已访问。包含(&n){
堆栈。向后推_(n);
}
while!stack.is_为空(){
设n2=stack.pop_front().unwrap();
设mut eflag=false;
插入(n2);
对于0..mst.node_count()中的n3{
如果mst.find_edge(n_到_ni[n2],n_到_ni[n3])是_some(){
eflag=真;
如果!已访问。包含(&n3){
堆叠。推回(n3);
设mut fflag=false;
对于路由中的r.iter_mut(){
如果r[0]==n2{
r、 向前推(n3);
fflag=真;
}如果r[r.len()-1]==n2,则为else{
r、 推回(n3);
fflag=真;
}如果r[0]==n3,则为else{
r、 向前推(n2);
fflag=真;
}如果r[r.len()-1]==n3,则为else{
r、 推回(n2);
fflag=真;
}
}
如果{
//未找到,请创建新矢量
让mut vd=VecDeque::default();
vd.推回(n2);
vd.推回(n3);
路线。推(vd)