好多基础知识都没补完,只好看到、用到一个赶紧补全一个,并且保证下次需要的时候直接用,不用回来再补;
其实这个算法是在补同余最短路的时候用到的,当时突然发现理解算法导论上的原理甚至有效性证明,但是就是没办法写出来合适的代码。。于是到处寻找可以用来试验最短路径算法的试验场(当时学矩阵快速米的时候也是找了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 }
时间: 2024-10-15 18:27:22