L2-001紧急救援 (dijkstra算法应用)
前提是会dijkstra算法🙂本篇会解决dijkstra大部分问题,在末尾会有一个总结
解题思路
首先这题需要使用dijkstra算法,所以需要开三个数组
-
g[N][N]用来记录边长
-
d[N]用来记录点到源块的距离
-
st[N]用来记录是否已经被收编到源块里
在这个基础上,还需要几个数组来应对题目 -
w[N] 用来记录最大救援队数量
-
power[N] 用来记录每个城市的救援队数量
求最大救援队数量的思路是:
{
如果最短路距离更小的时候,w[j] = power[j] + w[t]
如果距离相等,就要进行比较,找出最大的那个,用w[j] 与 w[t] + power[j] 进行比较
} -
num[N] 用来记录最短路数量 (最短路计数洛谷P1144 , 只不过这题要用堆优化版本)
{
求最短路数的思路是 :
更新邻居的时候,如果有更小的距离,就继承t的最短路数,如图:
![最短路]()
如果有相等的距离 说明有同样小的距离能到j, 就加上另一个最短路数
}
-
pre[N] 题目要求输出路径 , 所以需要记录最短路情况
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 1010;
int g[N][N];
int d[N];
bool st[N];
int power[N];
int num[N];
int w[N];
int pre[N];
int n,m,ori,tar;
void dijkstra()
{
memset(d,0x3f,sizeof d);
memset(st,0,sizeof st);
d[ori] = 0;
num[ori] = 1;
w[ori] = power[ori];
pre[ori] = -1;
for(int i = 1 ; i <= n ;i++)//控制循环次数
{
int t = -1;
for(int j = 0 ; j < n ; j++)//剩下的点中找最小,下标从0开始
if(!st[j] && (t == -1 || d[j] < d[t])) t = j;
st[t] = true;
for(int j = 0 ; j < n ; j++)
{
if(g[t][j] == 0x3f3f3f3f) continue;
if( d[t] + g[t][j] < d[j] )
{
d[j] = d[t] + g[t][j];
num[j] = num[t] ;
w[j] = w[t] + power[j];
pre[j] = t;
}
else if(d[j] == d[t] + g[t][j]) {
num[j] += num[t];//说明有个新的节点
if(w[j] < w[t] + power[j])
{
w[j] = w[t] + power[j] ;
pre[j] = t;
}
}
}
}
cout<<num[tar]<<" "<<w[tar]<<endl;
vector<int> trace;
int k = tar ;
while(k != -1)
{
trace.push_back(k);
k = pre[k];
}
for(int i = trace.size() -1 ;i >= 0 ; i--)
{
cout<<trace[i];
if(i != 0) cout<<" ";
}
cout<<endl;
}
int main()
{
cin>>n>>m>>ori>>tar;
memset(g,0x3f,sizeof g);
for(int i = 0 ; i < n ; i++) cin>>power[i];
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
g[a][b] = min(g[a][b] , c);
g[b][a] = min(g[b][a],c);
}
dijkstra();
return 0;
}
总结:
-
由于是无向图,所以存的时候需要对称存,同时还可能有重边(就本题而言题目不严谨),所以取最小值
-
对于非负权边,可以不判断自环,因为自环唯一会对代码产生影响的地方是 自环松弛 , 也就是如果某个点有负权自环,才会成功进行松弛,
当d[u] + w[u][u] < d[u]进行的时候才是自环产生影响的地方,而如果是非负权边,左边一定是大于右边的,不会进行任何更新,如果是负权边,实际上
dijkstra算法无法处理,只能适用spfa或者bellman。 -
因为dijkstra算法需要n次松弛 : 每次都要找离源块最近的点,一共有n个点,所以需要松弛n次,因此外层需要一个n次循环
-
不要漏掉st数组的应用,每有一个点进入源块,都要进行标记,下次它不能再作为“最近的点”。


浙公网安备 33010602011771号