递归寻找图的最短距离和最短路径进行剪枝

文章详细描述了如何使用C++实现Dijkstra算法求解图中两点间的最短路径,并介绍了剪枝技术来避免重复计算,通过map存储已找到的结果。
摘要由CSDN通过智能技术生成

图的结构

用C++语言表示

char graph[5][5] = {
        {0,1,-1,4,2},
        {1,0,8,3,3},
        {-1,8,0,-1,7},
        {4,3,-1,0,5},
        {2,3,7,5,0}
    };

为什么需要剪枝?

为什么需要剪枝?

因为在递归的过程有需要重复的问题节点,在前面已经找到了结果,不需要再查找。将结果存储在一个map中,每次查找前先查找map。

怎么剪枝,用一张图表示

在上图中用不同的颜色表示相同的问题节点。剪枝过程,就如同去掉相同的节点,只留下一个。

C++代码如下:

#include <iostream>
#include <array>
#include <vector>
#include <list>
#include <algorithm>
#include <map>
#include <algorithm>

using namespace std;
using std::array;
struct Distance;

struct Distance
{
    int len;
    Distance()
    {
        len = -1;
    }
    Distance(int n)
    {
        len = n;
    }
    bool operator>(const Distance & dist)
    {
        if(this->len == -1)
        {
            return true;
        }
        else if(dist.len == -1)
        {
            return false;
        }
        else
        {
            return this->len > dist.len;
        }
    }
    bool operator==(const Distance & dist)
    {
        return this->len == dist.len;
    }
    bool operator!=(const Distance & dist)
    {
        return this->len != dist.len;
    }
    Distance  operator+(const Distance & dist)
    {
        if(this->len == -1 || dist.len == -1)
        {
            return Distance(-1);
        }
        else
        {
            return Distance(this->len + dist.len);
        }
    }
    friend std::ostream & operator<<(std::ostream & out, Distance dist)
    {
        out << "len:" <<dist.len;
    }
};

void printf_list(const list<int> & l)
{
    printf("\n");
    for(auto it = l.begin(); it != l.end(); it++)
    {
        cout << *it << "<";
    }
    printf("\n");
}
//记录点到点的结构体
struct PtoPKey
{
    int x;
    int y;
    PtoPKey(int x, int y)
    {
        this->x = x;
        this->y = y;
    }
    bool operator!=(const PtoPKey & other)const
    {
        return (other.x != x) || (other.y != y);   
    }
    bool operator==(const PtoPKey & other)const
    {
        return (other.x == x) && (other.y == y);
    }
    bool operator<(const PtoPKey & other)const
    {
        return (x < other.x) || ((x == other.x) && (y < other.y));
    }
    friend ostream & operator<<(ostream & out, PtoPKey other)
    {
        out << "src:" << other.x << " dest:" <<other.y << endl;
        return out;
    }
};
//记录路径,最短距离和最短路径的个数
struct routeValue
{
    Distance len;
    int num;
    vector<list<int>> routes;
    routeValue()
    {
        this->len = 0;
        num = 0;
    }
    routeValue(Distance len, int num,  vector<list<int>> routes)
    {
        this->len = len;
        this->routes = routes;
        this->num = num;
    };
    void add_route(list<int> & route, Distance len)
    {
        if(len > (this->len))
        {
            return;
        }
        else if(len == (this->len))
        {
            this->num++;
            this->routes.push_back(route);
        }
        else
        {
            this->num = 1;
            this->len = len;
            this->routes.clear();
            this->routes.push_back(route);
        }
    }
    friend ostream  & operator<<(ostream & out,routeValue & other)
    {
        for (int i = 0; i < other.num; i++)
        {
            out << "rout:";
            list<int> temp = other.routes[i];
            for(auto it = temp.begin(); it != temp.end(); it++)
            {
                out << *it << ">";
            }
            out << endl;
        }
        out << "length:" <<  other.len << endl;
        return out;

    }
};

class Graph
{
private:
    /* data */
    int count_;
    map<PtoPKey,Distance> m_;
public:
    Graph(/* args */);
    Graph(const char * graph, int count);
    Distance getTwoPointDistance(int src, int dest)const;
    int getCount()const;
friend  ostream & operator<<(std::ostream & out, const Graph & graph);
    ~Graph();
};

Graph::Graph(/* args */)
{
    count_ = 0;
}
Graph::Graph(const char * graph, int count)
{
    count_ = count;
    for (int i = 0; i < count_; i++)
    {
        for (int j = 0; j < count_; j++)
        {
            m_[PtoPKey(i,j)] = Distance(*(graph+i*count_+j));
        }
    }
}

ostream & operator<<(std::ostream & out, const Graph & graph)
{
    int count = graph.getCount();
     for (int i = 0; i < count; i++)
    {
        for (int j = 0; j < count; j++)
        {
            out  << graph.getTwoPointDistance(i,j) << " ";
        }
        out << std::endl;
        
    }
    return out;
}

Distance Graph::getTwoPointDistance(int src, int dest)const
{
    Distance distance = m_.at(PtoPKey(src, dest));
    return distance;
}
int Graph::getCount()const
{
    return count_;
}

Graph::~Graph()
{
}


Distance MinDistance(const Graph & graph, const PtoPKey PToP,vector<list<int>> & routes, map<PtoPKey, routeValue> & m, int step)
{
    // cout << __FUNCTION__ << __LINE__<< endl;
    // hashmap剪枝
    map<PtoPKey, routeValue>::iterator it = m.find(PtoPKey(PToP.x, PToP.y));   
    if(it != (m.end()))
    {
        routes = m[PtoPKey(PToP.x, PToP.y)].routes;
        return m[PtoPKey(PToP.x, PToP.y)].len;
    }
    routes[0].push_back(PToP.x);//记录已经走过的点
    step++;
    if(PToP.x == PToP.y)
    {
        
        Distance d = Distance(0);
        routeValue routeV;
        routeV.add_route(routes[0], d);
        m[PtoPKey(PToP.x, PToP.y)] = routeV;

        return d;
    }
    else if(step >= graph.getCount())//最多经过w个点
    {

        return Distance(-1);
    }
    else
    {
       vector<list<int>> list_min;
       Distance len_min = 0;
       int flag = 0;
       for(int i=0; i < graph.getCount(); i++)
       {
         if(graph.getTwoPointDistance(PToP.x, i) != -1)//判断src点是否能够到达i点
         {
            //避免在原点打转
            if (i == PToP.x)
            {
                continue;
            }              
            vector<list<int>> routes_temp;
            routes_temp.push_back(list<int>());
            if(flag == 0)
            {
                len_min = MinDistance(graph, PtoPKey( i, PToP.y), routes_temp, m,step) + graph.getTwoPointDistance(PToP.x, i);
                list_min = routes_temp;
                flag = 1;
            }
            else
            {
                Distance t = MinDistance(graph ,PtoPKey(i, PToP.y), routes_temp, m, step) + graph.getTwoPointDistance(PToP.x, i);
                if(len_min > t)
                {
                    len_min = t;
                    list_min = routes_temp;
                }
                else if(len_min == t)
                {
                    vector<list<int>> temp;
                    temp.insert(temp.end(), list_min.begin(), list_min.end());
                    temp.insert(temp.end(), routes_temp.begin(), routes_temp.end());
                    list_min = temp;
                }
            }
         }
       } 
        //避免前方无路,返回Distance(-1),表示前面不可到达
       if(flag == 0)
       {
            return Distance(-1);
       }
       else if (len_min == -1)
       {
            return Distance(-1);
       }
       else
       {
            routeValue routeV;
            //将每个list_min的路径前面拼接上sours[0]的路径
            for (int i = 0; i < list_min.size(); i++)
            {
                list_min[i].push_front(PToP.x);
            }
            routeV.routes = list_min;
            
            routeV.len = len_min;
            routeV.num = list_min.size();
            m[PtoPKey(PToP.x, PToP.y)] = routeV;
            routes = list_min;
            return len_min;
       }
       
    }
}
int main()
{
    //不可达设置为-1
    char graph[5][5] = {
        {0,1,-1,4,2},
        {1,0,8,3,3},
        {-1,8,0,-1,7},
        {4,3,-1,0,5},
        {2,3,7,5,0}
    };
    Graph g((char*)(graph[0]), 5);
    cout << "graph:" <<int(*((char *)graph)) << std::endl;
    cout << g;
    map<PtoPKey, routeValue> m;
    vector<list<int>> route;
    route.push_back(list<int>());
    Distance lenth = MinDistance(g, PtoPKey(2, 3), route, m, 0);
    cout << lenth << endl;
    for (auto it = m.begin(); it != m.end(); it++)
    {
        cout << "---------------------------\n";
        cout << (*it).first << (*it).second;
        cout << "---------------------------\n";
    }
    
    return 0;
    
}

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
校园导航系统中,最短路径算法和全部路径算法都是非常重要的算法。Floyd算法是一种经典的求解任意两点之间最短路径算法,而DFS算法则是一种求解所有路径的算法。下面我将分别对这两种算法进行详细的阐述。 1. Floyd算法 Floyd算法是一种动态规划算法,用于求解带权有向中任意两点之间的最短路径。其基本思想是:对于中的每一对顶点,求出它们之间的最短路径,并将这个最短路径保存在一个矩阵中。具体实现过程如下: 首先,我们定义一个二维数组d[i][j],表示从顶点i到顶点j的最短路径长度。然后,我们对于每一对顶点i和j,我们都要尝试通过中间顶点k来缩短i到j的路径长度,即: ``` d[i][j] = min(d[i][j], d[i][k] + d[k][j]) ``` 在实现Floyd算法时,我们需要使用三重循环来遍历所有的顶点。具体来说,我们可以先枚举中间顶点k,再枚举起点i和终点j,然后根据上述公式来更新d[i][j]。 Floyd算法的时间复杂度为O(n^3),其中n为顶点数。虽然时间复杂度较高,但它的实现简单,且适用于所有的带权有向,因此在校园导航系统中,我们可以使用Floyd算法来求解最短路径。 2. DFS算法 DFS算法是一种递归算法,用于求解中所有路径。其基本思想是:从起点开始,递归地访问所有与之相邻的顶点,直到到达终点或者访问过所有的顶点。具体实现过程如下: 首先,我们定义一个数组path来保存当前路径,以及一个数组visited来记录每个顶点是否已经被访问过。然后,我们从起点开始递归地访问所有与之相邻的顶点,直到到达终点或者访问过所有的顶点。具体来说,我们可以先将起点加入到path中,然后标记起点为已访问。接着,我们从起点出发,访问与之相邻的所有顶点,并对每个相邻顶点递归地调用DFS函数。在递归调用结束后,我们需要将当前顶点从path中删除,并将其标记为未访问,以便于访问其他路径。 在实现DFS算法时,我们需要遍历所有的路径,因此时间复杂度为O(n!),其中n为顶点数。由于时间复杂度较高,因此在实际应用中,我们需要对DFS算法进行剪枝优化,以提高其效率。 综上所述,Floyd算法和DFS算法都是校园导航系统中常用的算法。Floyd算法可以求解任意两点之间的最短路径,而DFS算法可以求解所有路径。在实际应用中,我们可以根据具体的需求来选择合适的算法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值