Description
给出一个有向图,请输出从某一点出发到所有点的最短路径长度。
Input
第一行包含三个整数N、M、S,分别表示点的个数、有向边的个数、出发点的编号。
接下来M行每行包含三个整数Fi、Gi、Wi,分别表示第i条有向边的出发点、目标点和长度。
Output
一行,包含N个用空格分隔的整数,其中第i个整数表示从点S出发到点i的最短路径长度(若S=i则最短路径长度为0,若从点S无法到达点i,则最短路径长度为2147483647)
Sample Input
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
Sample Output
0 2 4 3
Data Size & Hint
Time : 1000MS
Memory : 128M
Data Size:
对于20%的数据:N<=5,M<=15
对于40%的数据:N<=100,M<=10000
对于70%的数据:N<=1000,M<=100000
对于100%的数据:N<=10000,M<=500000
luogu.org非常良心的模板练习
首先,我们来看一个裸的SPFA的代码。虽然理论上SFPA的复杂度为O(KE),并且K一般小于2。可实测证明,这样非常裸的写SPFA会被卡掉。一共10个测试点,TLE了6个。。。写了个读入优化并没有什么用。。捂脸.jpg。。
#include <cstdio>
#include <queue>
using namespace std;
inline int getint()
{
int r = 0, k = 1;
char c = getchar();
for(; c < '0' || c > '9'; c = getchar())
if(c == '-') k = -1;
for(; c >= '0' && c <= '9'; c = getchar())
r = r * 10 + c - '0';
return r * k;
}
const int maxn = 500005;
const int INF = 1009999999;
int n, m, x, y, z, cnte, S, T;
int dis[maxn], h[maxn];
bool vis[maxn];
queue <int> q;
struct Edge
{
int to, next, w;
} edge[maxn];
void ins(int x, int y, int z)
{
edge[++cnte].to = y;
edge[cnte].next = h[x];
edge[cnte].w = z;
h[x] = cnte;
}
void SPFA()
{
for(int i = 1; i <= n; i++)
{
dis[i] = INF;
vis[i] = false;
}
dis[S] = 0;
q.push(S);
vis[S] = true;
int now;
while(!q.empty())
{
now = q.front();
q.pop();
vis[now] = false;
for(int i = h[now]; i; i = edge[i].next)
{
if(dis[edge[i].to] > dis[now] + edge[i].w)
{
dis[edge[i].to] = dis[now] + edge[i].w;
if(!vis[edge[i].to])
{
q.push(edge[i].to);
vis[edge[i].to] = true;
}
}
}
}
}
int main()
{
n = getint();
m = getint();
S = getint();
for(int i = 1; i <= m; i++)
{
x = getint();
y = getint();
z = getint();
ins(x, y, z);
}
for(int i = 1; i <= n; i++)
{
if(S == i) dis[i] = 0;
T = i;
SPFA();
if(dis[i] == INF) dis[i] = 2147483647;
}
for(int i = 1; i < n; i++)
{
printf("%d ", dis[i]);
}
printf("%d\n", dis[n]);
return 0;
}
那么既然裸的SPFA会被卡的惨不忍睹,那么我们考虑将其优化一下。
这里用到的优化是SLF策略,即 Small Label First。设要加入的节点是j,队首元素为i,若dis[j] < dis[i],则将j插入队首,否则插入队尾。
这里就要用到双端队列,用STL中的deque容器实现即可。
具体代码如下:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <deque>
using namespace std;
inline int getint()
{
int r = 0, k = 1;
char c = getchar();
for(; c < '0' || c > '9'; c = getchar())
if(c == '-') k = -1;
for(; c >= '0' && c <= '9'; c = getchar())
r = r * 10 + c - '0';
return r * k;
}
const int maxn = 500005;
const int INF = 1009999999;
int n, m, x, y, z, cnte, S, T;
int dis[maxn], h[maxn];
bool vis[maxn];
deque <int> q;
struct Edge
{
int to, next, w;
} edge[maxn];
void ins(int x, int y, int z)
{
edge[++cnte].to = y;
edge[cnte].next = h[x];
edge[cnte].w = z;
h[x] = cnte;
}
void SPFA()
{
for(int i = 1; i <= n; i++)
{
dis[i] = INF;
vis[i] = false;
}
dis[S] = 0;
q.push_back(S);
vis[S] = true;
int now;
while(!q.empty())
{
now = q.front();
q.pop_front();
vis[now] = false;
for(int i = h[now]; i; i = edge[i].next)
{
if(dis[edge[i].to] > dis[now] + edge[i].w)
{
dis[edge[i].to] = dis[now] + edge[i].w;
if(!vis[edge[i].to])
{
if(!q.empty() || dis[q[0]] < dis[edge[i].to])
{
q.push_back(edge[i].to);
}
else
{
q.push_front(edge[i].to);
}
vis[edge[i].to] = true;
}
}
}
}
}
int main()
{
n = getint();
m = getint();
S = getint();
for(int i = 1; i <= m; i++)
{
x = getint();
y = getint();
z = getint();
ins(x, y, z);
}
for(int i = 1; i <= n; i++)
{
if(S == i) dis[i] = 0;
T = i;
SPFA();
if(dis[i] == INF) dis[i] = 2147483647;
}
for(int i = 1; i < n; i++)
{
printf("%d ", dis[i]);
}
printf("%d\n", dis[n]);
return 0;
}
当然,我们还可以考虑一下用堆优化过的Dijkstra。
代码如下:
/*
Problem: 3371 User: saruka
Memory: 28101K Time: 639MS
Language: G++ Result: Accepted
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
inline int getint()
{
int r = 0, k = 1;
char c = getchar();
for(; c < '0' || c > '9'; c = getchar())
if(c == '-') k = -1;
for(; c >= '0' && c <= '9'; c = getchar())
r = r * 10 + c - '0';
return r * k;
}
const int INF = 0x3f;
const int maxn = 500005;
int dis[maxn];
bool vis[maxn];
vector <int> G[10001];
int n, m, S;
struct Edge
{
int u,v,w;
} edge[maxn];
struct HeapNode
{
int d, u;
bool operator < (const HeapNode& rhs)const {
return d > rhs.d;
}
};
void dijkstra(int s)
{
priority_queue<HeapNode> q;
memset(dis, INF, sizeof(dis));
dis[s] = 0;
q.push((HeapNode){0, s});
while(!q.empty())
{
HeapNode x = q.top();
q.pop();
int u = x.u;
if(vis[u]) continue;
vis[u] = true;
for(int i = 0; i < G[u].size(); i++)
{
Edge& e = edge[G[u][i]];
if(dis[e.v] > dis[u] + e.w)
{
dis[e.v] = dis[u] + e.w;
q.push((HeapNode){dis[e.v], e.v});
}
}
}
}
int main()
{
n = getint();
m = getint();
S = getint();
for(int i = 1; i <= m; i++)
{
edge[i].u = getint();
edge[i].v = getint();
edge[i].w = getint();
G[edge[i].u].push_back(i);
}
dijkstra(S);
for(int i = 1; i < n; i++)
{
if(dis[i] == 0x3f3f3f3f) dis[i] = 2147483647;
printf("%d ", dis[i]);
}
printf("%d\n", dis[n]);
return 0;
}
Powered By Saruka
Copyright © 2016 All Rights Reserved.