PTA: 天梯地图 [狄杰斯特拉+堆优化+链式前向星]

题目

输入样例1:
10 15
0 1 0 1 1
8 0 0 1 1
4 8 1 1 1
5 4 0 2 3
5 9 1 1 4
0 6 0 1 1
7 3 1 1 2
8 3 1 1 2
2 5 0 2 2
2 1 1 1 1
1 5 0 1 3
1 4 0 1 1
9 7 1 1 3
3 1 0 2 5
6 3 1 2 1
5 3
输出样例1:
Time = 6: 5 => 4 => 8 => 3
Distance = 3: 5 => 1 => 3
输入样例2:
7 9
0 4 1 1 1
1 6 1 3 1
2 6 1 1 1
2 5 1 2 2
3 0 0 1 1
3 1 1 3 1
3 2 1 2 1
4 5 0 2 2
6 5 1 2 1
3 5
输出样例2:
Time = 3; Distance = 4: 3 => 2 => 5

思路

两种路径,两次狄杰斯特拉就可以了。

代码

#include <cstdio>
#include <queue>
#include <map>
#include <cstring>
#include <set>
#include <stack>

using namespace std;

typedef pair<int, int> PII;
const int maxn = 505;
struct Edge{
    int to, l, t, next;
}edge[maxn*maxn];
int tot = -1;
int head[maxn*maxn];
void add(int u, int v, int l, int t) {
    ++tot;
    edge[tot].to = v;
    edge[tot].l = l;
    edge[tot].t = t;
    edge[tot].next = head[u];
    head[u] = tot;
}
int dist[maxn], tme[maxn];
int pathd[maxn], patht[maxn];
int cnt[maxn], lenth[maxn];
bool operator<(const PII& a, const PII& b) {
    return a.second > b.second;
}
int s, d;
priority_queue<PII> que;

void dij1() {
    memset(dist, 0x3f, sizeof(dist));
    memset(cnt, 0, sizeof(cnt));
    set<int> vis;
    dist[s] = 0;
    cnt[s] = 1;
    que.push({s, 0});
    while(que.size()) {
        auto tmp = que.top(); que.pop();
        if(vis.count(tmp.first)) continue;
        vis.insert(tmp.first);
        for(int i = head[tmp.first]; i != -1; i = edge[i].next) {
            int tl = edge[i].l + dist[tmp.first];
            if(tl < dist[edge[i].to]) {
                dist[edge[i].to] = tl;
                pathd[edge[i].to] = tmp.first;
                cnt[edge[i].to] = cnt[tmp.first]+1;
                que.push({edge[i].to, tl});
            }
            else if(tl == dist[edge[i].to] && cnt[edge[i].to]>cnt[tmp.first]+1) {
                cnt[edge[i].to] = cnt[tmp.first]+1;
                pathd[edge[i].to] = tmp.first;
                que.push({edge[i].to, tl});
            }
        }
    }
}
void dij2() {
    memset(tme, 0x3f, sizeof(tme));
    memset(lenth, 0x3f, sizeof(lenth));
    set<int> vis;
    tme[s] = 0;
    lenth[s] = 0;
    que.push({s, 0});
    while(que.size()) {
        auto tmp = que.top(); que.pop();
        if(vis.count(tmp.first)) continue;
        vis.insert(tmp.first);
        for(int i = head[tmp.first]; i != -1; i = edge[i].next) {
            int tl = edge[i].t + tme[tmp.first];
            if(tl < tme[edge[i].to]) {
                tme[edge[i].to] = tl;
                patht[edge[i].to] = tmp.first;
                lenth[edge[i].to] = lenth[tmp.first]+edge[i].l;
                que.push({edge[i].to, tl});
            }
            else if(tl == tme[edge[i].to] && lenth[edge[i].to]>lenth[tmp.first]+edge[i].l) {
                lenth[edge[i].to]=lenth[tmp.first]+edge[i].l;
                patht[edge[i].to] = tmp.first;
                que.push({edge[i].to, tl});
            }
        }
    }
}

int main(void)
{
  //  freopen("in.txt", "r", stdin);
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; ++i) {
        head[i] = pathd[i] = patht[i] = -1;
    }
    int u, v, o, l, t;
    while(m--) {
        scanf("%d%d%d%d%d", &u, &v, &o, &l, &t);
        add(u, v, l, t);
        if(!o)
            add(v, u, l, t);
    }
    scanf("%d%d", &s, &d);
    stack<int> ansDis, ansTim;
    dij1(); dij2();
    ansDis.push(d);
    int i = pathd[d];
    while(i != -1) {
        ansDis.push(i);
        i = pathd[i];
    }
    ansTim.push(d);
    i = patht[d];
    while(i != -1) {
        ansTim.push(i);
        i = patht[i];
    }
    if(ansDis == ansTim) {
        printf("Time = %d; Distance = %d:", tme[d], dist[d]);
        printf(" %d", ansDis.top()); ansDis.pop();
        while(ansDis.size()) {
            printf(" => %d", ansDis.top()); ansDis.pop();
        }
    }
    else {
        printf("Time = %d:", tme[d]);
        printf(" %d", ansTim.top()); ansTim.pop();
        while(ansTim.size()) {
            printf(" => %d", ansTim.top()); ansTim.pop();
        }
        printf("\nDistance = %d:", dist[d]);
        printf(" %d", ansDis.top()); ansDis.pop();
        while(ansDis.size()) {
            printf(" => %d", ansDis.top()); ansDis.pop();
        }
    }
    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
狄杰斯特拉(Dijkstra)算法,也叫单源最短路径算法,是用于计算一个节点到其他所有节点的最短路径的算法。该算法常用于路由算法或作为其他图算法的一个子模块。 以下是狄杰斯特拉算法的基本思路: 1. 将所有节点分成两个集合:已知最短路径的节点集合和未知最短路径的节点集合。初始时,已知最短路径的节点集合只有起点,其他节点都在未知最短路径的节点集合中。 2. 对于所有的未知最短路径的节点,计算其到起点的距离,选择距离最小的节点加入已知最短路径的节点集合中。 3. 对于新加入已知最短路径的节点,更新其他未知最短路径的节点到起点的距离。 4. 重复步骤2和步骤3,直到所有节点都加入到已知最短路径的节点集合中。 以下是使用C++实现狄杰斯特拉算法的示例代码: ```c++ #include <iostream> #include <climits> using namespace std; #define V 6 // 图的顶点数 #define INF INT_MAX // 定义无穷大 // 查找未知最短路径中距离起点最近的节点 int minDistance(int dist[], bool sptSet[]) { int minDist = INT_MAX, minIndex; for(int i = 0; i < V; i++) { if(!sptSet[i] && dist[i] <= minDist) { minDist = dist[i]; minIndex = i; } } return minIndex; } // 执行狄杰斯特拉算法的函数 void dijkstra(int graph[V][V], int start) { int dist[V]; // 存储节点到起点的距离 bool sptSet[V]; // 存储节点是否已知最短路径 // 初始化dist数组和sptSet数组 for(int i = 0; i < V; i++) { dist[i] = INT_MAX; sptSet[i] = false; } dist[start] = 0; // 起点到起点的距离为0 for(int i = 0; i < V - 1; i++) { int u = minDistance(dist, sptSet); // 找到未知最短路径中距离起点最近的节点 sptSet[u] = true; // 将该节点加入已知最短路径的节点集合中 // 更新其他未知最短路径的节点到起点的距离 for(int v = 0; v < V; v++) { if(!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v]) { dist[v] = dist[u] + graph[u][v]; } } } // 输出最短路径 cout << "节点\t\t到起点的距离" << endl; for(int i = 0; i < V; i++) { cout << i << "\t\t" << dist[i] << endl; } } int main() { int graph[V][V] = { {0, 2, 4, 0, 0, 0}, {2, 0, 1, 4, 2, 0}, {4, 1, 0, 0, 3, 0}, {0, 4, 0, 0, 3, 2}, {0, 2, 3, 3, 0, 2}, {0, 0, 0, 2, 2, 0} }; dijkstra(graph, 0); // 以0节点为起点执行狄杰斯特拉算法 return 0; } ``` 这个示例代码中的图是一个无向图,其邻接矩阵存储在graph数组中。运行程序后,将输出每个节点到起点的最短距离。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值