单源最短路dijkstra算法&&优化史

一下午都在学最短路dijkstra算法,总算是优化到了我能达到的水平的最快水准,然后列举一下我的优化历史,顺便总结总结

最朴素算法:

    邻接矩阵存边+贪心||dp思想,几乎纯暴力,luoguTLE+MLE,

    算优点??:但好写好想,比下面的代码短了差不多一半。

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

int main()
{
    int a[100][100],point,i,j,k,number,t1,t2,t3,u,n,min,book[10]={0},dis[10];
    int inf=99999999;
    scanf("%d %d\n",&point,&number);
    int x;
    cin>>x; 
    for(int i=1;i<=point;i++)
      for(int j=1;j<=point;j++)
        if(i==j)a[i][j]=0;
        else
          a[i][j]=inf;
    
    for(int i=1;i<=number;i++)
    {
        cin>>t1>>t2>>t3;
        a[t1][t2]=t3;
    }
    
    for(int i=1;i<=point;i++)
      dis[i]=a[1][i];
      
    for(int i=1;i<=point-1;i++)
    {
        min=inf;
        for(int j=1;j<=point;j++)
          if(book[j]==0&& dis[j]<min)
          {
              min=dis[j];
              u=j;
          }
        book[u]=1;
        for(int k=1;k<=point;k++)
        {
            if(a[u][k]<inf)
              if(dis[k]>dis[u]+a[u][k])
                dis[k]=dis[u]+a[u][k];
        }
    }
    for(int i=1;i<=point;i++)
      cout<<i<<" "<<dis[i]<<endl;
    return 0;          
}

 

第一次优化是前向星存边,

比上面最朴素的大量省空间,也省了部分时间,luogu上共用时1400ms+,一个点max接近五百。

 1 #include<iostream>
 2 #include <algorithm>
 3 #include <string>
 4 #include <cmath>
 5 #include <cstring>
 6 # include <cstdio> 
 7 #define maxi 2147483647;
 8 
 9 using namespace std;
10 
11 struct node
12 {
13     int z;//子节点
14     int val;//权值
15     int nexty;//最近父节点相同边编号 
16 }edge[1000000];
17 int head[20000];//某点为父节点运出的最后一条边
18 int cnt=0,curr;// 边id
19 
20 inline void add(int a,int b,int c)//建立边向前星
21 {
22    cnt++;
23    edge[cnt].z=b;
24    edge[cnt].val =c;
25    edge[cnt].nexty =head[a];
26    head[a]=cnt;
27 }
28 
29 int main()
30 {
31     bool visit[20001]={0};//是否已经加入最短路 
32     long long dis[20001];//最短路存值 
33     int n,m,s;
34     int a,b,c;
35     
36     scanf("%d%d%d",&n,&m,&s);
37     for(int i=1;i<=n;i++)//初始化边权值为无穷 
38       dis[i]=maxi;
39     for(int i=0;i<m;i++)
40     {
41         scanf("%d%d%d",&a,&b,&c);
42         add(a,b,c);
43     }
44     //读入 
45     curr=s;
46     dis[s]=0;//到最初点距离为零 
47     long long minn;
48     
49     while(!visit[curr])
50     {
51         visit[curr]=true;
52         for(int i=head[curr];i!=0;i=edge[i].nexty )
53         {
54             if(!visit[edge[i].z]&&dis[edge[i].z]>dis[curr]+edge[i].val )
55               dis[edge[i].z]=dis[curr]+edge[i].val;
56         }
57         minn=2147483647;
58         for (int i=1;i<=n;i++)
59           if(!visit[i]&&minn>dis[i])
60           {
61               minn=dis[i];
62               curr=i;
63           }
64     }
65     for (int i=1;i<=n;i++)
66       printf("%lld ",dis[i]);
67     return 0;
68 }
dijkstra优化1

最后的优化使代码长达近百行

主要运用:快读快写,优先队列(堆),前向星存边

不过这次优化使用结构体存边的时候发生了玄学错误,现在还是找不出错,不过用几个数组存边就AC了???

个人是喜欢结构体的,毕竟好写也整齐,但是没通过的话就不发出来了

这个复杂度又比上一个程序降低了不少,luogu 共用时500+ms,单个点max160+ms,比上一个快了大概3,4倍

下面这个是ac的数组存边。

 

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <queue>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <stdio.h>
 7 #include <string.h>
 8 #define maxn 10005
 9 #define maxm 500005
10 #define inf 2147483647
11 
12 using namespace std;
13 
14 int n,m,cnt=0;
15 bool visit[maxn];
16 int head[maxm],next[maxm],v[maxm],w[maxm],dist[maxn];
17 
18 inline int read()  
19 {  
20     char ch;  
21     int a=0;  
22     while(!(((ch=getchar())>='0')&&(ch<='9')));  
23     a*=10;a+=ch-'0';  
24     while(((ch=getchar())>='0')&&(ch<='9'))a*=10,a+=ch-'0';  
25     return a;  
26 }
27 
28 void write(int x)
29 {
30     if(x<0) putchar('-'),x=-x;
31     if(x>9)write(x/10);
32     putchar(x%10+'0');
33     return ;
34 }
35 
36 struct cmp
37 {
38     bool operator()(int x,int y)
39     {
40         return dist[x]>dist[y];
41     }
42 };
43 
44 void add(int a,int b,int c)
45 {
46     v[cnt]=b;
47     w[cnt]=c;
48     next[cnt]=head[a];
49     head[a]=cnt++;
50     return ;
51 }
52 
53 void dijk(int s)
54 {
55     priority_queue<int,vector<int>,cmp> q2;
56     while(!q2.empty() )
57       q2.pop() ;
58     dist[s]=0;
59     q2.push(s);
60     while(!q2.empty() )
61     {
62         int x=q2.top() ;
63         q2.pop() ;
64         if(!visit[x])
65         {
66             visit[x]=true;
67             for(int i=head[x];i!=-1;i=next[i])
68             {
69                 int y=v[i];
70                 dist[y]=min(dist[y],dist[x]+w[i]);
71                 q2.push(y);
72             }
73         }
74     }
75     return ;
76 }
77 
78 int main()
79 {
80     int s;
81     n=read();
82     m=read();
83     s=read();
84     memset(head,-1,sizeof(head));
85     memset(visit,0,sizeof(visit));
86     for(int i=1;i<=m;i++)
87     {
88         int a,b,c;
89         a=read(),b=read(),c=read();
90         add(a,b,c);
91     }
92     for(int i=1;i<=n;i++)
93       dist[i]=inf;
94     dijk(s);
95     for(int i=1;i<=n;i++)
96       write(dist[i]),putchar(' ');
97     return 0;
98 }
dijkstra优化2

 

 

注意!这不是最优化dijkstra,只是个人能力能达到的最优化了。。。

写那么长的代码还是挺有成就感的

转载于:https://www.cnblogs.com/SuperGoodGame/p/9052990.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值