51nod_1459 最短路 dijkstra 特调参数

好多基础知识都没补完,只好看到、用到一个赶紧补全一个,并且保证下次需要的时候直接用,不用回来再补;

其实这个算法是在补同余最短路的时候用到的,当时突然发现理解算法导论上的原理甚至有效性证明,但是就是没办法写出来合适的代码。。于是到处寻找可以用来试验最短路径算法的试验场(当时学矩阵快速米的时候也是找了51nod上面的一到基础题作为测试的)来熟悉和不全最短路相关基础知识。

首先是DIJKSTRA 

对于DIJKSTRA首先是个贪心算法,每次从集合中选择一条没有走过的最短路径来作为新的边,到达新的节点。在以当前找到的这条边更新所有可达的边——所谓的松弛操作。

可以证明,在n次这样的松弛操作之后,可以求得单元最短路(具体证明见算法导论)

这题的要求比单元最短路相对更高些,他要求找到最短路且权重最高的路径。因而应当在每次进行松弛操作时进行更新——当且仅当路径长度相同时选择更大的权重,其他时候选择更短的边的权重。

DIJKSTRA如下:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const long long INF=1e12+233;
 5 const long long MAXN=1e3+233;
 6 long long dp[MAXN];
 7 long long point[MAXN];
 8 long long mon[MAXN];
 9 long long path[MAXN][MAXN];
10 long long n,m,start,end;
11 
12 void init()
13 {
14     cin>>n>>m>>start>>end;
15     memset(mon,0,sizeof(mon));
16     for(int i=0;i<MAXN;++i)
17         for(int j=0;j<MAXN;++j)path[i][j]=INF;
18     for(int i=0;i<n;++i)
19     {
20         cin>>point[i];
21         dp[i]=INF;
22     }
23     for(int i=0;i<m;++i)
24     {
25         int a,b,p;
26         cin>>a>>b>>p;
27         path[a][b]=p;
28         path[b][a]=p;
29     }
30 }
31 int v[MAXN];
32 void dijkstra()
33 {
34     memset(v,0,sizeof(v));
35     int x=start;
36     mon[start]=point[start];
37     dp[start]=0;        //dijkstra初始化,应当以最起始点为0点
38     for(int i=0;i<n;++i)
39     {
40         long long mini=INF;
41         for(int j=0;j<n;++j)
42         {
43             if(!v[j]&&dp[j]<mini)
44             {
45                 x=j;
46                 mini=dp[j];
47             }
48         }v[x]=1;        //标记出现过的点
49         for(int j=0;j<n;++j)
50         {
51             if(!v[j]&&dp[j]>dp[x]+path[x][j])
52             {
53             
54                 mon[j]=mon[x]+point[j];
55             }if(!v[j]&&dp[j]==dp[x]+path[x][j])//注意更新时确保该点没有被走到,否则可能出现重复更新
56             {
57                 mon[j]=max(mon[j],mon[x]+point[j]);
58             }
59             
60             dp[j]=min(dp[x]+path[x][j],dp[j]);
61         }
62     }cout<<dp[end]<<" "<<mon[end]<<endl;
63 }
64 int main()
65 {
66     cin.sync_with_stdio(false);
67     init();
68     dijkstra();
69     return 0;
70 }

 堆优化的dijkstra,来自刘汝佳的蓝书,同样要注意简要修改下。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 const long long MAXN=500+233;
  5 const long long INF=1e7+2;
  6 
  7 
  8 
  9 class Edge
 10 {
 11     public:
 12         long long from,to,dist;
 13 };
 14 
 15 
 16 class HeapNode
 17 {
 18     public:
 19         long long d,u;
 20         bool operator < (const HeapNode& h1)const
 21         {
 22             return this->d>h1.d;
 23         }
 24 };
 25 
 26 long long mon[MAXN];
 27 long long point[MAXN];
 28 long long n1,m1,start,end;
 29 
 30 struct Dijkstra
 31 {
 32     long long n,m;
 33     vector<Edge> edges;
 34     vector<long long> G[MAXN];
 35     bool done[MAXN];
 36     long long d[MAXN];
 37     long long p[MAXN];
 38     
 39     void init(long long n)
 40     {
 41         this->n=n;
 42         for(long long i=0;i<n;++i)
 43         {
 44             G[i].clear();
 45         }edges.clear();
 46     }
 47     
 48     void AddEdge(long long from,long long to,long long dist)
 49     {
 50         edges.push_back((Edge){from,to,dist});
 51         m=edges.size();
 52         G[from].push_back(m-1);
 53     }
 54     
 55     void dijkstra(long long s)
 56     {
 57         priority_queue<HeapNode> Q;
 58         for(long long i=0;i<n;++i)d[i]=INF;
 59         d[s]=0;
 60         memset(done,0,sizeof(done));
 61         Q.push((HeapNode){0,s});
 62         mon[s]=point[s];
 63         while(!Q.empty())
 64         {
 65             HeapNode x=Q.top();Q.pop();
 66             long long u=x.u;
 67             if(done[u])continue;
 68             done[u]=true;
 69             for(long long i=0;i<G[u].size();++i)
 70             {
 71                 Edge &e=edges[G[u][i]];
 72                 if(d[e.to]>d[u]+e.dist)
 73                 {
 74                     d[e.to]=d[u]+e.dist;
 75                     p[e.to]=G[u][i];
 76                     Q.push((HeapNode){d[e.to],e.to});
 77                     mon[e.to]=mon[u]+point[e.to];
 78                 }else if(d[e.to]==d[u]+e.dist)
 79                 mon[e.to]=max(mon[u]+point[e.to],mon[e.to]);
 80             }
 81         }
 82     }
 83 };
 84 
 85 int main()
 86 {
 87     cin.sync_with_stdio(false);
 88     Dijkstra d1;
 89     cin>>n1>>m1>>start>>end;
 90     for(long long i=0;i<n1;++i)cin>>point[i];
 91     d1.init(n1);
 92     for(long long i=0;i<m1;++i)
 93     {
 94         long long a,b,p;cin>>a>>b>>p;
 95         d1.AddEdge(a,b,p);
 96         d1.AddEdge(b,a,p);
 97     }
 98     d1.dijkstra(start);
 99     
100     cout<<d1.d[end]<<" "<<mon[end]<<endl;
101     
102     
103     
104     return 0;
105 }

 Bellman_Ford算法:
首先,算法思路:设定某有向图中,不存在负环,则对于每条最短路,都会在每一轮松弛中,得到至少一条最短路。

若有向图G中,有一条最短路:A->B->C->D->E,那么因为起始节点为A,则A->B的最短路径会在第一轮松弛操作时被找到。而后操作也是同理。接下来的每个最短路元素都会在未来的某一次松弛操作中被找到。因为每轮松弛操作都至少找到一个元素,所以我们应当认为

原文地址:https://www.cnblogs.com/rikka/p/7308878.html