zoukankan      html  css  js  c++  java
  • 单源最短路径模板(弱化版)

    题目描述:传送门

    题解思路:

    此题目如果直接套用单源最短路径的模板并且不使用优化(即无最小堆或者优先队列帮助实现),并以邻接矩阵的方式储存点和边及权值,最多只能得到70分,测试点卡在MLE上。

    在无优化的单源最短路径模板上,倘若使用前向星的方法来实现边和点的储存(只换了储存方式,其他的操作和思想没变),便能轻松通过所有测试数据。

    那么什么是前向星呢?

    请点击此处(说白了就是一种储存结构,虽然实现比邻接矩阵更复杂,但是时间和空间上都优于邻接矩阵)

    首先贴出邻接矩阵的代码(主要是为了方便理解单源最短路径的模板是如何实现的,基本就是直接套用模板加上微弱的改动)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int MAX=10005;
     4 int INFTY=2147483647;
     5 int WHITE=0;
     6 int BLACK=1;
     7 int GRAY=2;
     8 int n,m,s;
     9 int a[10005][10005]={0};
    10 
    11 //邻接矩阵
    12 void dijkstra(){ 
    13     int color[MAX];
    14     int d[MAX];
    15     for(int i=1;i<=n;i++){
    16         d[i]=INFTY;
    17         color[i]=WHITE;
    18     } 
    19     d[s]=0;
    20     
    21     color[s]=GRAY;
    22     
    23     while(1){
    24         int u=-1;
    25         int minv=INFTY;
    26         for(int i=1;i<=n;i++){
    27             if(minv>d[i]&&color[i]!=BLACK){
    28                 u=i;
    29                 minv=d[i];
    30             }
    31         }
    32         if(u==-1)    break;
    33         color[u]=BLACK;    
    34         for(int j=1;j<=n;j++){
    35             if(color[j]==BLACK||a[u][j]==0) continue;
    36 
    37             if(d[j]>d[u]+a[u][j]) {
    38                 d[j]=d[u]+a[u][j];
    39                 color[j]=GRAY; 
    40             }
    41         }
    42     }
    43     for(int i=1;i<=n;i++){
    44         cout<<d[i]<<" ";
    45     }
    46 }
    47 int main(){    
    48     int u,v,w;
    49     
    50     cin>>n>>m>>s;        //注意 题目所给的编号范围是1-n 所以使用模板时需要注意修改范围 
    51     for(int i=1;i<=m;i++){
    52         cin>>u>>v>>w;
    53         if(a[u][v]==0){            //目的是防止重复输入  导致最短直接距离被后面更大的值替代了 
    54             a[u][v]=w;
    55         }else{
    56             if(w<a[u][v]){
    57                 a[u][v]=w;
    58             }
    59         }
    60     }
    61     
    62     dijkstra();
    63     return 0;
    64 }

    现在贴出使用前向星后的代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int MAX=10005;
     4 long long INFTY=2147483647;        //由于题目说明无法达到则设置成2^31-1,故直接可将初始距离设为2^31-1 
     5 int WHITE=0;
     6 int BLACK=1;
     7 int GRAY=2;
     8 int n,m,s;
     9 int cnt=0;
    10 
    11 struct edge{
    12     int to;
    13     int w;
    14     int next;
    15 }e[500005];
    16 int head[10005];
    17 
    18 void dijkstra(){ 
    19     int color[MAX];
    20     long long d[MAX];                    //因为是高精 所以要注意测试数据里面出现较大的结果 
    21     for(int i=1;i<=n;i++){
    22         d[i]=INFTY;
    23         color[i]=WHITE;
    24     }
    25     d[s]=0;
    26     
    27     color[s]=GRAY;
    28     
    29     while(1){
    30         int u=-1;
    31         long long minv=INFTY;
    32         for(int i=1;i<=n;i++){
    33             if(minv>d[i]&&color[i]!=BLACK){
    34                 u=i;
    35                 minv=d[i];
    36             }
    37         }
    38         if(u==-1)    break;
    39         color[u]=BLACK;    
    40         int temp=head[u];            //取出与u连接的第一条边,temp为其编号 
    41         for(int k=temp;~k;k=e[k].next){
    42             if(color[e[k].to]==BLACK||e[k].w==0) continue;
    43             
    44             if(d[e[k].to]>d[u]+e[k].w){
    45                 d[e[k].to]=d[u]+e[k].w;
    46                 color[e[k].to]=GRAY; 
    47             }
    48         }
    49     
    50     }
    51     for(int i=1;i<=n;i++){
    52         cout<<d[i]<<" ";
    53     }
    54 }
    55 void add(int u,int v,int w){            //向前星存边         实际上是倒序存边     编号从1开始 
    56     e[cnt].to=v;        //边的终点 
    57     e[cnt].w=w;            //权值 
    58     e[cnt].next=head[u];
    59     head[u]=cnt;            //更新与点u连接的第一条边的编号 
    60     cnt++;
    61 }
    62 int main(){
    63     int u,v,w;
    64     
    65     cin>>n>>m>>s;        //注意 题目所给的编号范围是1-n 所以使用模板时需要注意修改范围 
    66     
    67     memset(head,-1,sizeof(head));
    68     for(int i=1;i<=m;i++){
    69         cin>>u>>v>>w;
    70         add(u,v,w);
    71     }
    72     
    73     dijkstra();
    74     return 0;
    75     
    76 }

    由上面可以对比看见,主要思想没有改变,只是在储存和遍历的时候的方式不同而已。

  • 相关阅读:
    java基础
    mysql入门
    基础整理
    遍历列表的两种方式
    oracle常用操作
    DIV+CSS网页布局技巧实例1:设置网页整体居中的代码
    html+css 淘宝首页静态页面案例
    WEB前端开发规范文档+CSS命名规范
    day05-苏宁易购导航html
    day04-html
  • 原文地址:https://www.cnblogs.com/xwh-blogs/p/12781447.html
Copyright © 2011-2022 走看看