题意:
给你点数、边数、起点、终点,哪些边,让你求起点到终点最短路径。是一道很适合拿来练手的纯裸模板题。
思路:
本题数据范围:1≤T≤2500,1≤C≤6200,朴素dijk、堆优化dijk、bellman_ford、spfa算法都可以过,选一个自己喜欢的即可,注意 该图是无向图。
下面用四个方法解决这道题。
朴素版dijkstra做法 O(n^2) 226ms
#include<bits/stdc++.h>
using namespace std;
int T, C;
#define inf 0x3f3f3f3f
const int N = 2510, M = 12420;
int dist[N], g[N][N];
bool st[N];
void dijk(int ts, int te)
{
memset(dist, 0x3f, sizeof dist);
dist[ts] = 0;
for(int i=0;i<T;++i)
{
int t = -1;
for(int j=1;j<=T;++j)
{
if(!st[j]&&(dist[t]>dist[j]||t==-1))
t = j;
}
st[t] = true;
for(int j=1;j<=T;++j) dist[j] = min(dist[j], dist[t]+g[t][j]);
}
}
int main()
{
int ts, te;
cin>>T>>C>>ts>>te;
memset(g, 0x3f,sizeof g);
for(int i=0;i<C;++i)
{
int a, b, w;
cin>>a>>b>>w;
g[a][b] = g[b][a] = min(g[a][b], w);
}
dijk(ts, te);
cout<<dist[te]<<endl;
return 0;
}
堆优化dijkstra做法 O(mlogn) 37ms
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
#define x first
#define y second
int t, c;
const int N = 2510, M = 12420;
#define inf 0x3f3f3f3f
int dist[N], h[N];
int e[M], ne[M], w[M], idx;
bool st[N];
void add(int a, int b, int c)
{
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
void dijk(int ts, int te)
{
memset(dist, 0x3f,sizeof dist);
dist[ts] = 0;
priority_queue<pii, vector<pii>, greater<pii>> pq;
pq.push({dist[ts], ts});
while(pq.size())
{
pii tmp = pq.top();
pq.pop();
int ver = tmp.y, distance = tmp.x;
if(st[ver]) continue;
st[ver] = true;
for(int i=h[ver]; ~i; i=ne[i])
{
int j=e[i];
if(dist[j]>distance+w[i])
{
dist[j] = distance + w[i];
pq.push({dist[j], j});
}
}
}
}
int main()
{
int ts, te;
cin>>t>>c>>ts>>te;
memset(h, -1,sizeof h);
while(c--)
{
int a, b, c;
cin>>a>>b>>c;
add(a, b, c), add(b, a, c);
}
dijk(ts, te);
cout<<dist[te]<<endl;
return 0;
}
bellman_ford做法 O(nm) 378ms
#include<bits/stdc++.h>
using namespace std;
int t, c;
const int N = 2510, M = 12420;
int dist[N];
bool st[N];
struct edge
{
int a, b, w;
} edg[M];
void bellman_ford(int ts, int te)
{
memset(dist, 0x3f, sizeof dist);
dist[ts] = 0;
for (int i=0; i<t; ++i )
{
for (int j=1; j<=c; ++j )
{
//这里是唯一要注意的地方,双向边,一条边的两个端点的dist都要更新
int a = edg[j].a, b = edg[j].b, w = edg[j].w;
dist[b] = min(dist[b], dist[a] + w);
dist[a] = min(dist[a], dist[b] + w);
}
}
}
int main()
{
int ts, te;
cin>>t>>c>>ts>>te;
for(int i=1;i<=c;++i)
{
cin>>edg[i].a>>edg[i].b>>edg[i].w;
}
bellman_ford(ts, te);
cout<<dist[te]<<endl;
return 0;
}
spfa做法 平均情况下 O(m),最坏情况下 O(nm) 20ms
#include<bits/stdc++.h>
using namespace std;
const int N = 2510, M = 12420;
int t, c;
#define inf 0x3f3f3f3f
int dist[N];
int h[N], e[M], ne[M], w[M], idx;
bool st[N];
void add(int x, int y, int z){
e[idx] = y, ne[idx] = h[x], w[idx] = z, h[x] = idx++;
}
void spfa(int ts, int te)
{
memset(dist, 0x3f,sizeof dist);
dist[ts] = 0;
queue<int> q;
q.push(ts);
st[ts] = true;
while(q.size())
{
int t = q.front();
q.pop();
st[t] = false;
for(int i=h[t]; ~i; i=ne[i])
{
int j = e[i];
if(dist[j]>dist[t]+w[i])
{
dist[j] = dist[t]+w[i];
if(!st[j])
{
q.push(j);
st[j] = true;
}
}
}
}
}
int main()
{
int ts, te;
cin>>t>>c>>ts>>te;
memset(h, -1, sizeof h);
while(c--)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c), add(b, a, c);
}
spfa(ts, te);
cout<<dist[te]<<endl;
return 0;
}