有向无环图上的最长路径(DS图)

题解
  1. 这题一开始以为可以用dijkstra求解,但是实际上不行。原因在于最短路径问题中有最优子结构,即最短路径的子路径还是最短路径,dijkstra就是利用了这一点,而最长路径问题中没有该子结构。
  2. 实际上求最长路径是NP-hard问题,但是其有线性时间的解。对于有向无环图而言,先拓扑排序,再动态规划求解即可。这里和dijkstra一样是以最长求最长的思想,但是这里不像求最短一样能直接得到源点到某个点的最长距离,而如果拓扑有序后,就可以先取序列中靠前的点求最长,然后动态规划逐步求靠后点的最长距离。
  3. 求最长路径也就是求关键路径。
题目
问题 E: 有向无环图上的最长路径(DS图)
时间限制: 1 Sec  内存限制: 128 MB
提交: 3  解决: 2
[提交][状态][讨论版]
题目描述
求出下面有向图中,顶点“5”到其他所有顶点的最长路径和长度。

在这里插入图片描述

输入
根据上面的有向图结构,在内存中用邻接表(Adjacency List)存储该图。

第1行:顶点数

第2行:边数

第3行:一条有向边

第4行:一条有向边

……

输出
第1行:从50的最长路径,路径长度

第2行:从51的最长路径,路径长度

第3行:从52的最长路径,路径长度

第4行:从53的最长路径,路径长度

……

样例输入

8
13
5 4 0.35
4 7 0.37
5 7 0.28
5 1 0.32
4 0 0.38
0 2 0.26
3 7 0.39
1 3 0.29
7 2 0.34
6 2 0.40
3 6 0.52
6 0 0.58
6 4 0.93

样例输出

5 1 3 6 4 0 
5 1
5 1 3 6 4 7 2
5 1 3
5 1 3 6 4
5 1 3 6
5 1 3 6 4 7
代码(dijkstra)(WA)
#include <iostream>
using namespace std;

class ListNode
{
    int vertex;
    double weight;
    ListNode *next;
public:
    ListNode(){next = NULL;}
    friend class Graph;
};

class Graph
{
private:
    int vexnum;
    int edgenum;
    ListNode **adjlist;
    int *s;
    double *dist;
    int *path;
    int IsOver();
    void DisplayPath(int i);
public:
    Graph();
    ~Graph();
    void Dijkstra(int vex);
};

Graph::Graph()
{
    int i;
    cin>>vexnum>>edgenum;
    adjlist = new ListNode*[vexnum];
    s = new int[vexnum];
    dist = new double[vexnum];
    path = new int[vexnum];
    for(i=0; i<vexnum; i++)
    {
        s[i] = 0;
        dist[i] = 0;
        path[i] = -1;
        adjlist[i] = new ListNode;
    }
    for(i=0; i<edgenum; i++)
    {
        ListNode *p;
        int startvex, endvex;
        double weight;
        cin>>startvex>>endvex>>weight;
        p = new ListNode;
        p->weight = weight;
        p->vertex = endvex;
        p->next = adjlist[startvex]->next;
        adjlist[startvex]->next = p;
    }
}

Graph::~Graph()
{
    delete []adjlist;
    delete []s;
    delete []dist;
    delete []path;
}

int Graph::IsOver()
{
    for(int i=0; i<vexnum; i++)
    {
        if(!s[i])
            return 0;
    }
    return 1;
}

void Graph::Dijkstra(int vex)
{
    ListNode *p;
    p = adjlist[vex];
    while(p->next)
    {
        p = p->next;
        dist[p->vertex] = p->weight;
        path[p->vertex] = vex;
    }
    s[vex] = 1;
    while(!IsOver())
    {
        int temp;
        double maxweight = 0;
        for(int i=0; i<vexnum; i++)
            if(dist[i]>maxweight && !s[i])
            {
                maxweight = dist[i];
                temp = i;
            }
        s[temp] = 1;
        p = adjlist[temp];
        while(p->next)
        {
            p = p->next;
            if(dist[temp]+p->weight>dist[p->vertex] && !s[p->vertex])
            {
                dist[p->vertex] = dist[temp]+p->weight;
                path[p->vertex] = temp;
            }
        }
    }
    for(int i=0; i<vexnum; i++)
    {
        cout<<dist[i]<<' '<<path[i]<<endl;
    }
}

int main(void)
{
    Graph myGraph;
    myGraph.Dijkstra(5);
}
代码(拓扑+动态规划)(AC)
#include <iostream>
#include <queue>
#include <stack>
using namespace std;

class ListNode
{
    int vertex;
    double weight;
    ListNode *next;
public:
    ListNode(){next = NULL;}
    friend class Graph;
};

class Graph
{
private:
    int vexnum;
    int edgenum;
    ListNode **adjlist;
    double **matrix;
    int *S;
    int *s;
    double *dist;
    int *path;//由于还是以最长求最长,所以这里还是可以只用一个path数组记录到每个点的路径。
    int IsOver();
    void DisplayPath(int i);
    void TopologicalSort();
public:
    Graph();
    ~Graph();
    void Dijkstra();
};

Graph::Graph()
{
    int i, j;
    cin>>vexnum>>edgenum;
    adjlist = new ListNode*[vexnum];
    s = new int[vexnum];
    S = new int[vexnum];
    dist = new double[vexnum];
    path = new int[vexnum];
    matrix = new double*[vexnum];
    for(i=0; i<vexnum; i++)
    {
        s[i] = 0;
        dist[i] = 0;
        path[i] = -1;
        adjlist[i] = new ListNode;
        matrix[i] = new double[vexnum];
        for(j=0; j<vexnum; j++)
            matrix[i][j] = 0;
    }
    for(i=0; i<edgenum; i++)
    {
        ListNode *p;
        int startvex, endvex;
        double weight;
        cin>>startvex>>endvex>>weight;
        p = new ListNode;
        p->weight = weight;
        p->vertex = endvex;
        p->next = adjlist[startvex]->next;
        adjlist[startvex]->next = p;
        matrix[startvex][endvex] = weight;
    }
}

Graph::~Graph()
{
    delete []adjlist;
    delete []s;
    delete []dist;
    delete []path;
    for(int i=0; i<vexnum; i++)
        delete []matrix[i];
    delete []matrix;
}

int Graph::IsOver()
{
    for(int i=0; i<vexnum; i++)
    {
        if(!s[i])
            return 0;
    }
    return 1;
}

void Graph::DisplayPath(int i)
{//在不断根据path逆向求路径时需要用一个栈来跟着保存,每次调用只输出到一个点i的路径。
    stack<int> s;
    s.push(i);
    while(path[i]!=-1)
    {
        i = path[i];
        s.push(i);
    }
    while(!s.empty())
    {
        i = s.top();
        s.pop();
        cout<<i<<' ';
    }
    cout<<endl;
}

void Graph::TopologicalSort()
{
    int num = 0;
    while(!IsOver())
    {
        int i, j;
        for(i=0; i<vexnum; i++)
        {
            if(!s[i])
            {
                for(j=0; j<vexnum; j++)
                {
                    if(matrix[j][i])
                        break;
                }
                if(j==vexnum)
                    break;
            }
        }
        s[i] = 1;
        S[num] = i;
        num++;
        for(j=0; j<vexnum; j++)
            matrix[i][j] = 0;
    }
}

void Graph::Dijkstra()
{
    TopologicalSort();
    int i;
    ListNode *q;
    for(i=0; i<vexnum; i++)
    {
        int temp = S[i];
        q = adjlist[temp];
        while(q->next)
        {
            q = q->next;
            if(dist[q->vertex]<dist[temp]+q->weight)
            {
                dist[q->vertex] = dist[temp]+q->weight;
                path[q->vertex] = temp;
            }
        }
    }
    for(i=0; i<vexnum; i++)
    {
        if(i!=S[0])
            DisplayPath(i);
    }
}

int main(void)
{
    Graph myGraph;
    myGraph.Dijkstra();
}
  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: DS是一种有向,其中每个边都有一个权值。最短路径问题是指在中找到从一个起点到一个终点的最短路径。这个问题可以使用Dijkstra算法或Bellman-Ford算法来解决。Dijkstra算法是一种贪心算法,它从起点开始,每次选择距离起点最近的未访问节点,并更新与该节点相邻的节点的距离。Bellman-Ford算法则是一种动态规划算法,它通过多次迭代来更新每个节点的最短路径。这两种算法都可以解决最短路径问题,但是Dijkstra算法在处理稠密时更快,而Bellman-Ford算法可以处理带有负权边的。 ### 回答2: ds是一种数据结构,用于表示有向,并提供了一种最短路径的求解算法。最短路径是指从起始点到目标点的一条最短的路径,其中路径度可以用一个数值来衡量,例如边的权值或者距离等。最短路径算法可以应用于很多领域,诸如导航、网络路由、路线规划等。 ds采用了多个数据结构来实现最短路径算法,包括堆、优先队列、散列表等。算法包括了三个主要步骤,分别是初始化、松弛和更新。 在初始化阶段,起始点被标记为距离为0,并加入到一个优先队列中。其他点被标记为无穷大距离,以便松弛算法能够更新它们。 在松弛阶段,算法会遍历优先队列中的点,并尝试更新它们的距离。具体地说,算法会遍历每个点的邻居,计算从起始点到邻居的距离,并将这个距离加上该点的距离值,然后比较新的距离值与当前距离值,如果新的更小,则更新距离值。 在更新阶段,算法会把被更新的点重新添加到优先队列中。这样,优先队列中的点会按照它们的距离值排序,从而保证算法能够找到最短路径。 总之,ds提供了一种快速、高效地求解最短路径的算法。它的实现相对简单,但可以在实际应用中取得良好的效果。值得注意的是,算法假设中不存在负权边,否则算法可能不能正确地计算出最短路径。 ### 回答3: DS 是一种基于数据结构的,常用于论算法的优化。在 DS 上求最短路径,与在原始上求最短路径的思路类似,都是利用一些经典算法来解决。但是 DS 可以优化的存储方式和查找过程,使得在某些的特征下,能够大大提高求解最短路径的效率。 DS 中,每个节点存储了该节点到一些固定“距离”范围内的节点的最短距离,相邻节点之间的边权重不一定相等。因此,在 DS 上求最短路径的算法,需要结合这一特征进行设计。以下介绍两种常见的求最短路径的算法: 1. Dijkstra 算法:该算法基于贪心算法的思想,每次选取与起点的距离最短的点作为下一步的起点,直到到达终点。但在 DS 上,由于节点之间的边权重不等,需要使用优先队列来动态维护每个节点的距离,再根据距离来确定下一个起点。时间复杂度为 O(ElogV),其中 E 为边数,V 为节点数。 2. A* 算法:该算法结合了 Dijkstra 算法和启发式搜索的思想,以终点为目标做启发式,每次扩展时都选取当前的最佳(启发式函数值最小)节点进行扩展。在 DS 中,启发式函数可以取当前节点到终点的距离,再乘以一个权重系数。通过启发式,能够使搜索效率更高,但前提是能够设计一个合适的启发式函数。时间复杂度也是 O(ElogV)。 总之,在 DS 上求最短路径与在普通上求最短路径的算法思路类似,但需要结合 DS 的特征进行适当的改进。常用的算法有 Dijkstra 算法和 A* 算法。同样的,选择哪种算法,应该依据具体问题而定,考虑算法的时间复杂度、空间复杂度和实际应用中的效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值