AcWing
3305. 作物杂交
SPFA
. SPFA
与Dijkstra
的区别是,SPFA
可以用来搜索含负权边图的单源最短路径,但是不能包括负环(只能用来检测负环);而Dijkstra
只能用于非负权图。SPFA
算法的时间复杂度在$O(kE)\sim O(VE)$,$k$为一个较小的常数,稀疏图上效率较高。一般来说,Dijkstra
算法的时间复杂度比SPFA
算法更稳定,Dijkstra
算法(堆优化)能过的情况下,SPFA
可以过掉大部分测试点。
SPFA
算法是Bellman-Ford
算法的一种优化,其算法思想基于动态规划(DP). 它维护一个队列,每次取出队首元素,visited
变为0
,遍历它的邻接点,对于被更新(dist
更新为更小值)的点,如果它当前不在队列(visited
为0),则将其加入队列,visited
变为1
. 循环上述操作,直至队列为空。
对于本题,w
表示种子生长的时间,e
表示邻接点(配对点),target
表示杂交产生的点,M
应该取二倍的杂交方案数,因为如果a
与b
可以配对,那么b
与a
也可以配对。本题也可以看作,已经拥有的种子连接了一个超级源点。
#include <bits/stdc++.h>
using namespace std;
int n, m, k, t;
const int N = 2010, M = 100010 * 2;
int w[N], h[N], e[M], target[M], ne[M], idx;
queue<int> q;
int dist[N];
bool visited[N];
void add(int a, int b, int c){
e[idx] = b, target[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void spfa(){
while(!q.empty()){
int top = q.front();
visited[top] = 0;
q.pop();
for(int i = h[top]; ~i; i = ne[i]){
int j = e[i];
if(max(dist[top], dist[j]) + max(w[top], w[j]) < dist[target[i]]){
dist[target[i]] = max(dist[top], dist[j]) + max(w[top], w[j]);
if(!visited[target[i]]) q.push(target[i]);
visited[target[i]] = 1;
}
}
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cin.tie(0);
cin >> n >> m >> k >> t;
memset(h, -1, sizeof h);
memset(visited, false, sizeof visited);
memset(dist, 0x3f, sizeof dist);
for(int i = 1; i <= n; i++) cin >> w[i];
while(m--){
int temp;
cin >> temp;
q.push(temp);
visited[temp] = 1;
dist[temp] = 0;
}
while(k--){
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
add(b, a, c);
}
spfa();
cout << dist[t] << endl;
return 0;
}