题目比较简单,讲两种做法
法一、二都是用的朴素dijkstra算法
法一:反向建图 求终点s到每个起点的最短距离 O(T * (n^2 + n))(T表示多组测试数据)820ms
#include <bits/stdc++.h>
using namespace std;
const int N = 1010, M = 2e4+10;
#define inf 0x3f3f3f3f
int g[N][N], dist[N];
bool st[N];
int n, m, s;
int w;
int W[N];
int dijk(int s){
memset(dist, 0x3f, sizeof dist);
memset(st, false, sizeof st);
dist[s] = 0;
for(int i=0;i<n;++i){
int t = -1;
for(int j=1;j<=n;++j){
if(!st[j]&&(dist[t]>dist[j]||t==-1)){
t = j;
}
}
st[t] = true;
for(int j=1;j<=n;++j){
dist[j] = min(dist[j], dist[t] + g[t][j]);
}
}
int res = inf;
for(int i=0;i<w;++i){
res = min(res, dist[W[i]]);//求终点s到所有起点最短路的最小值
}
return res;
}
int main()
{
while(cin>>n>>m>>s)
{
memset(g, 0x3f, sizeof g);
for(int i=0;i<m;++i){
int p, q, t;
cin>>p>>q>>t;
g[q][p] = min(g[q][p], t);//注意是反向建图,加入的边就要反转
}
cin>>w;
for(int i=0;i<w;++i) cin>>W[i];
int ans = dijk(s);
if(ans==inf) cout<<-1<<endl;
else cout<<ans<<endl;
}
return 0;
}
法二 设置虚拟源点 求虚拟源点到终点s的最短距离 O(T * n^2) 339ms
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
#define inf 0x3f3f3f3f
int g[N][N], dist[N];
bool st[N];
int n, m, s;
int w;
int W[N];
int dijk(int s){
memset(dist, 0x3f, sizeof dist);
memset(st, false, sizeof st);
dist[0] = 0;
//由于加了一个点,因此每个for循环的次数都要加一
for(int i=0;i<n+1;++i){
int t = -1;
for(int j=0;j<=n;++j){
if(!st[j]&&(dist[t]>dist[j]||t==-1)){
t = j;
}
}
st[t] = true;
for(int j=0;j<=n;++j){
dist[j] = min(dist[j], dist[t] + g[t][j]);
}
}
return dist[s];//返回虚拟源点到终点s的最短距离
}
int main()
{
while(~scanf("%d%d%d", &n, &m, &s))
{
memset(g, 0x3f, sizeof g);
for(int i=0;i<m;++i){
int p, q, t;
scanf("%d%d%d", &p, &q, &t);
g[p][q] = min(g[p][q], t);
}
scanf("%d", &w);
for(int i=0;i<w;++i) scanf("%d", &W[i]), g[0][W[i]] = 0;//将虚拟源点到起点的距离都设置为0,因此所有起点到终点的最短路径就是虚拟源点到终点的最短路
int ans = dijk(s);
if(ans==inf) printf("-1\n");
else printf("%d\n" ,ans);
}
return 0;
}
|