链式前向星 + 优先队列 + 最短路 hdu-3790

本文介绍了一种解决特定最短路径问题的算法实现方法,该问题要求找出两点间距离最短且花费最小的路径。通过使用优先队列和额外数组记录路径花费,实现了对传统Dijkstra算法的有效扩展。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最短路径问题

 HDU - 3790 

给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。

Input

输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点。n和m为0时输入结束。 
(1<n<=1000, 0<m<100000, s != t)

Output

输出 一行有两个数, 最短距离及其花费。

Sample Input

3 2
1 2 5 6
2 3 4 5
1 3
0 0

Sample Output

9 11

需要用到优先队列

再开一个val数组记录花费

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
int m, n;
int a, b, d, p;
int s, t;
int tot;
int dis[maxn];
int vis[maxn];
int val[maxn];
int head[maxn];

struct node{
    int to;
    int next;
    int l;
    int v;
    node() {}
    node(int z, int x, int c, int y) : to(z), next(x), l(c), v(y) {}
} edge[maxn];

void edgeadd(int a, int b, int d, int p){
    edge[tot] = node(b, head[a], d, p);
    head[a] = tot++;
    edge[tot] = node(a, head[b], d, p);
    head[b] = tot++;
}

void init(){
    memset(head, -1, sizeof(head));
    memset(vis, 0, sizeof(vis));
    memset(dis, inf, sizeof(dis));
    memset(val, inf, sizeof(val));
    tot = 0;
}

struct heapnode{
    int di, li, u;
    heapnode() {}
    heapnode(int a, int b, int c) : di(a), li(b), u(c) {}
    bool operator < (const heapnode &rhs)const//重载
    {
        if(di == rhs.di)
            return li > rhs.li;//按花费从小到大排
        return di > rhs.di;//按距离从小到大排
    }
};
void dijktra(int str){
    priority_queue <heapnode> q;
    q.push(heapnode(0, 0, str));
    dis[str] = 0;
    val[str] = 0;
    while(!q.empty()){
        heapnode w = q.top();
        q.pop();
        int f = w.u;
        if(vis[f])
            continue;
        vis[f] = 1;
        for(int i = head[f]; i != -1; i = edge[i].next){
            int k = edge[i].to;
            if(dis[k] >= dis[f] + edge[i].l){
                if(dis[k] == dis[f] + edge[i].l){
                    if(val[k] <= val[f] + edge[i].v)
                        continue;
                }
                dis[k] = dis[f] + edge[i].l;
                val[k] = val[f] + edge[i].v;
                q.push(heapnode(dis[k], val[k], k));
            }
        }
    }


}

int main(){
    ios::sync_with_stdio(false);
    while(cin >> n >> m && n != 0 && m != 0){
        init();
        for(int i = 0; i < m; i++){
            cin >> a >> b >> d >> p;
            edgeadd(a, b, d, p);
        }
        cin >> s >> t;
        dijktra(s);
        cout << dis[t] << " " << val[t] << endl;
    }
    return 0;
}

 

### 链式前向星结构与深度优先遍历(DFS)的实现 链式前向星是一种高效的数据结构,用于存储图结构,尤其是在有向图中应用广泛。它结合了邻接表和链表的优点,能够以较为简洁的方式存储图的边信息,同时在图的遍历、最短路径算法、小生成树算法等场景中表现出色。其核心优势在于空间利用率高、代码实现简洁且遍历效率稳定[^2]。 #### 链式前向星的组成 链式前向星主要由两个数组组成: - `head[]`:记录每个顶点的第一条边的索引。 - `edges[]`:存储边的信息,通常包括目标顶点 `to`、下一条边的索引 `next`,以及可能的权重 `weight`。 #### DFS 算法实现 在链式前向星结构下,DFS 算法的实现可以通过递归或非递归方式进行。以下是一个基于链式前向星的深度优先遍历的递归实现示例: ```cpp #include <iostream> #include <vector> using namespace std; const int MAXN = 100005; // 假设大顶点数为 100005 struct Edge { int to; // 边的目标顶点 int next; // 下一条边的索引 } edges[MAXN]; int head[MAXN]; // 每个顶点的第一条边 int edgeCount = 0; // 边计数器 // 添加边函数 void addEdge(int u, int v) { edges[edgeCount].to = v; edges[edgeCount].next = head[u]; head[u] = edgeCount++; } bool visited[MAXN]; // 访问标记数组 // 深度优先遍历函数 void dfs(int node) { visited[node] = true; cout << node << " "; // 输出当前访问的顶点 // 遍历当前顶点的所有邻接点 for (int i = head[node]; i != -1; i = edges[i].next) { int neighbor = edges[i].to; if (!visited[neighbor]) { dfs(neighbor); } } } int main() { // 初始化 head 数组 memset(head, -1, sizeof(head)); // 示例:构建图 addEdge(0, 1); addEdge(0, 2); addEdge(1, 3); addEdge(1, 4); addEdge(2, 5); addEdge(2, 6); // 从顶点 0 开始进行深度优先遍历 dfs(0); return 0; } ``` #### 代码说明 - `addEdge` 函数用于向图中添加边,其中 `u` 是起点,`v` 是终点。 - `dfs` 函数是递归实现的深度优先遍历函数,通过 `visited` 数组记录已访问的顶点,避免重复访问。 - 在 `main` 函数中,通过 `addEdge` 添加了几条边,并从顶点 `0` 开始进行深度优先遍历。 #### 时间复杂度分析 链式前向星结构下的 DFS 算法的时间复杂度为 $O(V + E)$,其中 $V$ 是顶点数,$E$ 是边数。空间复杂度为 $O(V + E)$,主要用于存储图的边和顶点信息[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值