hdu 3790 最短路径问题

Problem Description

给你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
解题思路:解题关键先保证是最短距离,其次如果距离相等的话,再保证最小费用。首先要预处理一下,因为读入数据可能出现重边,如果不处理就会进行覆盖原来的权值,这样就出错了。
AC代码一Dijkstra:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int INF = 0x3f3f3f3f;
 4 const int MAXN = 1005;
 5 int n,m,a,b,d,p,s,t,dis[MAXN],cis[MAXN],cost[MAXN][MAXN],G[MAXN][MAXN];//dis数组记录当前节点离起点的最短路径,cis数组记录当前节点离起点的最小费用,cost数组和G数组分别记录费用和节点之间的关系
 6 bool vis[MAXN];
 7 void Dijkstra(){
 8     for(int i=1;i<=n;++i){//先默认初始化dis和cis为起点到各节点的最短路径和最小费用
 9         dis[i]=G[s][i];
10         cis[i]=cost[s][i];
11     }
12     dis[s]=cis[s]=0;vis[s]=true;//到自己的距离为0,且0花费
13     for(int i=1;i<n;++i){  //剩下遍历n-1个节点
14         int k=-1; //先标记为-1
15         for(int j=1;j<=n;++j)//查找dis中的最小权值
16             if(!vis[j] && (k==-1 ||dis[j]<dis[k]))k=j;//找到最小权值的下标
17         if(k==-1)break; //说明已经全部归纳了,直接退出当前循环,否则才可以进行下面的松弛操作
18         vis[k]=true;  //该点已经归纳最短路径的集合
19         for(int j=1;j<=n;++j){//更新起点到每个节点的最短路径
20             if(!vis[j]){  //如果还没有归纳进去
21                 if(dis[j]>dis[k]+G[k][j]){
22                     cis[j]=cis[k]+cost[k][j];
23                     dis[j]=dis[k]+G[k][j];
24                 }
25                 else if(dis[j]==dis[k]+G[k][j] && cis[j]>cis[k]+cost[k][j]) //如果当前多条最短路径,则取两者中较小费用
26                     cis[j]=cis[k]+cost[k][j];
27             }
28         }
29     }
30 }
31 int main()
32 {
33     while(~scanf("%d %d",&n,&m) && (m+n)){
34         for(int i=1;i<=n;++i){
35             for(int j=1;j<=n;++j)
36                 if(i==j)G[i][j]=cost[i][j]=0;//到自身的距离和费用都为0
37                 else G[i][j]=cost[i][j]=INF;//其余初始化为INF
38         }
39         memset(vis,false,sizeof(vis));
40         for(int i=1;i<=m;++i){
41             scanf("%d %d %d %d",&a,&b,&d,&p);
42             if(G[a][b]>d){//预处理,考虑到重边的情况
43                 G[a][b]=G[b][a]=d;
44                 cost[a][b]=cost[b][a]=p;
45             }
46             else if(G[a][b]==d && cost[a][b]>p)//如果a到b的距离等于原来的话,取最小费用
47                 cost[a][b]=cost[b][a]=p;
48         }
49         scanf("%d %d",&s,&t);
50         Dijkstra();
51         printf("%d %d
",dis[t],cis[t]);
52     }
53     return 0;
54 }

AC代码二(优先队列默认最大堆实现Dijkstra迪杰斯特拉算法):

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int INF = 0x3f3f3f3f;
 4 const int MAXN = 1005;
 5 int n,m,a,b,d,p,s,t,dis[MAXN],cis[MAXN],cost[MAXN][MAXN],G[MAXN][MAXN];//dis数组记录当前节点离起点的最短路径,cis数组记录当前节点离起点的最小费用,cost数组和G数组分别记录费用和节点之间的关系
 6 void Dijkstra(){
 7     priority_queue< pair<int,int> > que;//最大堆优先队列
 8     dis[s]=cis[s]=0;//到自己的距离为0,且0花费
 9     que.push(make_pair(-dis[s],s));//加上负号实现最大堆,便于取出最短路径
10     while(!que.empty()){
11         int k=que.top().second;//每次取出队首元素即最短路径
12         que.pop();//弹出队首元素
13         for(int i=1;i<=n;++i){  //更新邻边权值最小的邻接点
14             if(dis[i]>dis[k]+G[k][i]){
15                 cis[i]=cis[k]+cost[k][i];
16                 dis[i]=dis[k]+G[k][i];
17                 que.push(make_pair(-dis[i],i));  //如果有最小权值的邻接点,加入队列中去,记得加负号,因为这是最大堆
18             }
19             else if(dis[i]==dis[k]+G[k][i] && cis[i]>cis[k]+cost[k][i]) //如果当前多条最短路径,则取两者中较小费用
20                 cis[i]=cis[k]+cost[k][i];
21         }
22     }
23 }
24 int main()
25 {
26     while(~scanf("%d %d",&n,&m) && (m+n)){
27         for(int i=1;i<=n;++i)
28             dis[i]=cis[i]=INF;//全部初始化为INF无穷大
29         for(int i=1;i<=n;++i){
30             for(int j=1;j<=n;++j)
31                 if(i==j)G[i][j]=cost[i][j]=0;//到自身的距离和费用都为0
32                 else G[i][j]=cost[i][j]=INF;//其余初始化为INF
33         }
34         for(int i=1;i<=m;++i){
35             scanf("%d %d %d %d",&a,&b,&d,&p);
36             if(G[a][b]>d){//预处理,考虑到重边的情况
37                 G[a][b]=G[b][a]=d;
38                 cost[a][b]=cost[b][a]=p;
39             }
40             else if(G[a][b]==d && cost[a][b]>p)//如果a到b的距离等于原来的话,取最小费用
41                 cost[a][b]=cost[b][a]=p;
42         }
43         scanf("%d %d",&s,&t);
44         Dijkstra();
45         printf("%d %d
",dis[t],cis[t]);
46     }
47     return 0;
48 }
原文地址:https://www.cnblogs.com/acgoto/p/9045163.html