问题描述: 有n个点,m个边,每条边上有一个权值,求从s节点到e节点的最短路径,即途径路上的权值和为最小。
是求单起点,多终点最短路的问题。
dijkstra算法基本思想
1:设置一个distanse数组,存储从起始点s到各个节点的距离(权值和),distanse[i]即从s到i的最短路
2:初始状态,distanse[i]=mp[s][i],found[s]=1
3:每次从所有 1未访问的节点中 挑出 2distanse最小的点k choose() 进行松弛操作;
4:松弛操作。如果经过k到j的distanse小于原来的distanse 更新distanse
if(dis[k]+mp[k][j]<dis[j]) dis[j]=dis[k]+mp[k][j];
dijkstar 算法的时间复杂度是O(N^2)可以用对优化到O(N*LogN)级别
用了贪心的思想,只能用于正权边,带负权的会导致贪心的bug
本题是两个权,距离和cost,分优先级的进行dijkstra,比较水。
不过还是要注意数组下标别写错了,错一个就是WA!
dijkstra算法只有两个过程 1:选择下一个要操作的点 2:松弛
对图的存储使用 邻接矩阵 和 链式前向星 (感觉和邻接表是一回事)都是一样的,只要稍微改一下代码
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 1005 , INF = 0x3f3f3f; 5 int mp[maxn][maxn],dis[maxn],fond[maxn],cost[maxn][maxn],wei[maxn]; 6 int n,m,a,b,d,p,s,t; 7 8 void input() 9 { 10 while(m--) 11 { 12 scanf("%d%d%d%d",&a,&b,&d,&p); 13 if(mp[a][b]>d) 14 { 15 mp[a][b]=mp[b][a]=d; 16 cost[a][b]=cost[b][a]=p; 17 } 18 else if(mp[a][b]==d) 19 { 20 cost[a][b]=cost[b][a]=min(cost[a][b],p); 21 } 22 } 23 cin>>s>>t; 24 } 25 26 int choose() 27 { 28 int cnt = -1,minn=INF; 29 for(int i=1;i<=n;i++) 30 { 31 if(!fond[i]&&minn>dis[i]) 32 { 33 minn=dis[i]; 34 cnt=i; 35 } 36 } 37 return cnt; 38 } 39 40 void dijkstra() 41 { 42 for(int i=1;i<=n;i++) 43 { 44 fond[i]=0; 45 dis[i]=mp[s][i]; 46 wei[i]=cost[s][i]; 47 } 48 fond[s]=1; 49 for(int i=1;i<=n;i++) 50 { 51 int k=choose(); 52 if(k==-1)return ; 53 fond[k]=1; 54 for(int j=1;j<=n;j++) 55 { 56 if(!fond[j]) 57 { 58 if(dis[k]+mp[k][j]<dis[j]){ 59 dis[j]=dis[k]+mp[k][j]; 60 wei[j]=wei[k]+cost[k][j]; 61 } 62 else if( dis[j]==dis[k]+mp[k][j]) 63 { 64 wei[j]=min(wei[j],wei[k]+cost[k][j]); 65 } 66 } 67 } 68 } 69 } 70 71 int main() 72 { 73 while(cin>>n>>m,n,m) 74 { 75 memset(mp,INF,sizeof(mp)); 76 memset(cost,INF,sizeof(cost)); 77 input(); 78 dijkstra(); 79 cout<<dis[t]<<" "<<wei[t]<<endl; 80 } 81 return 0; 82 }
下面的HDU1874是经典模板题
dis[t]=0一定要加上
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 205, INF = 10000000; 5 int mp[maxn][maxn],found[maxn],dis[maxn]; 6 int n,m,s,t,a,b,x; 7 void input() 8 { 9 //memset(mp,INF,sizeof(mp)); 10 for(int i=0;i<n;i++) 11 for(int j=0;j<n;j++) 12 mp[i][j]=INF; 13 memset(found,0,sizeof(found)); 14 while(m--) 15 { 16 scanf("%d%d%d",&a,&b,&x); 17 if(x<mp[a][b]) mp[a][b]=mp[b][a]=x; 18 } 19 cin>>s>>t; 20 } 21 22 int choose() 23 { 24 int cnt=-1,minn=INF; 25 for(int i=0;i<n;i++) 26 { 27 if(!found[i]&&dis[i]<minn) 28 { 29 cnt=i;minn=dis[i]; 30 } 31 } 32 return cnt; 33 } 34 35 void dijkstra() 36 { 37 for(int i=0;i<n;i++) 38 { 39 dis[i]=mp[s][i]; 40 } 41 found[s]=1; 42 dis[s]=0; 43 for(int i=0;i<n;i++) 44 { 45 int k=choose(); 46 if(k==-1)return; 47 found[k]=1; 48 for(int j=0;j<n;j++) 49 { 50 if(!found[j]&&dis[k]+mp[k][j]<dis[j]) 51 { 52 dis[j]=dis[k]+mp[k][j]; 53 } 54 } 55 } 56 } 57 58 59 int main() 60 { 61 while(cin>>n>>m) 62 { 63 input(); 64 dijkstra(); 65 if(dis[t]==INF)cout<<"-1"<<endl; 66 else cout<<dis[t]<<endl; 67 68 } 69 return 0; 70 }