选择最佳线路
题面
思路
有两种思路,一种是我们将终点看成起点,反向建边跑最短路;
但是这种思路不太容易扩展;
这里介绍另一种思路;
我们建立一个虚拟起点,由这个点像各个起点连一条边权为0的边;
这样我们就将原问题从每个起点出发,到达终点的所有路线的距离最小值转换为了从虚拟起点出发,到达终点的所有路线的距离最小值;
然后跑单源最短路即可;
注意
这种思路可以扩展成多个起点,多个终点的形式;
与建立虚拟起点类似,我们建立一个虚拟终点即可;
注意了,这跟floyd
不一样;floyd
是可以求出任意点对的最短距离,也就是求出每个起点到每个终点的最短距离;
而我们这个是在有多个起点、多个终点的情况下,求出从中选任意一个起点到每个终点的最短距离;
Code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
const int N = 1e3 + 10,M = 3e4 + 10;
int n,m,T;
struct Edge{
int to,next,w;
}e[M];
int cnt,head[N],dist[N];
bool vis[N];//是否在队列中
const int INF = 0x3f3f3f3f;
void add(int u,int v,int w){
++cnt;
e[cnt].w = w;
e[cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt;
}
void spfa(){
queue<int> que;
que.push(0);
dist[0] = 0;
vis[0] = 1;
while(!que.empty()){
int u = que.front();
que.pop();
vis[u] = 0;
for(int i=head[u];i;i=e[i].next){
int to = e[i].to;
if(dist[to] > dist[u] + e[i].w){
dist[to] = dist[u] + e[i].w;
if(!vis[to]){
que.push(to);
vis[to] = 1;
}
}
}
}
dist[T] = dist[T] >= INF/2? -1 : dist[T];
}
void solve(){
memset(head,0,sizeof head);
memset(dist,0x3f,sizeof dist);
memset(vis,0,sizeof vis);
cnt = 0;
for(int i=1,u,v,w;i<=m;++i){
cin >> u >> v >> w;
add(u,v,w);
}
int start;
cin >> start;
for(int i=1,v;i<=start;++i){
cin >> v;
//建立虚拟源点
add(0,v,0);
}
spfa();
cout << dist[T] << '\n';
}
signed main(){
std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
//cin >> t;
while(cin >> n >> m >> T)
solve();
return 0;
}