• 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 }
  • 相关阅读:
    C学习笔记——字符串操作
    抓取网站特定内容后直接入mysql库
    C语言笔记——时间运算
    SCP链接方式
    C学习笔记——数组
    免费HTTP数据抓包Fiddler2[4.6.1.2]以及显示中文包内容的方法
    近期要研究的jquery插件
    Always 英文技术网站一
    silverlight工具下载网址
    英文网站参照1
  • 原文地址:https://www.cnblogs.com/acgoto/p/9045163.html
Copyright © 2020-2023  润新知