您的位置:首页 > 其它

洛谷P3371 单源最短路径(Dijkstra+堆优化)

2017-07-16 20:59 447 查看

题目描述

如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度。

输入输出格式

输入格式:

第一行包含三个整数N、M、S,分别表示点的个数、有向边的个数、出发点的编号。

接下来M行每行包含三个整数Fi、Gi、Wi,分别表示第i条有向边的出发点、目标点和长度。

输出格式:

一行,包含N个用空格分隔的整数,其中第i个整数表示从点S出发到点i的最短路径长度(若S=i则最短路径长度为0,若从点S无法到达点i,则最短路径长度为2147483647)

输入输出样例

输入样例#1:

4 6 1

1 2 2

2 3 2

2 4 1

1 3 5

3 4 3

1 4 4

输出样例#1:

0 2 4 3

说明

时空限制: 1000ms,128M

数据规模:

对于20%的数据:N<=5,M<=15

对于40%的数据:N<=100,M<=10000

对于70%的数据:N<=1000,M<=100000

对于100%的数据:N<=10000,M<=500000

显然是道随便写个SPFA就能水掉的题,发两个Dijkstra + 堆优化的板子

【代码1】STL

#include <iostream>
#include <cstdio>
#include <algorithm>
#define fs first
#define sc second

using namespace std;
const int N = 1e4 + 5, M = 5e5 + 5;
int dis
, cnt = 1; bool vis
;
pair<int, int> h[M];
int n, m, src;

inline int get()
{
char ch; int res = 0;
while ((ch = getchar()) < '0' || ch > '9');
res = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9')
res = (res << 3) + (res << 1) + ch - '0';
return res;
}

inline void put(int x)
{
if (x > 9) put(x / 10);
putchar(x % 10 + 48);
}

struct Edge
{
int to, cst; Edge *nxt;
}a[M], *T = a, *lst
;

inline void addEdge(const int &z, const int &y, const int &x)
{
(++T)->nxt = lst[x]; lst[x] = T; T->to = y; T->cst = z;
}

inline void Dijkstra(const int &st)
{
for (int i = 1; i <= n; ++i) dis[i] = 2147483647;
h[0].fs = dis[st] = 0; h[0].sc = st; int x, y;
for (int i = 1; i <= n; ++i)
{
while (vis[h[0].sc] && cnt) pop_heap(h, h + cnt), --cnt;
if (!cnt) break;
x = h[0].sc, pop_heap(h, h + cnt), --cnt;
vis[x] = true;
for (Edge *e = lst[x]; e; e = e->nxt)
if (dis[y = e->to] > dis[x] + e->cst)
{
dis[y] = dis[x] + e->cst;
h[cnt].fs = -dis[y]; h[cnt++].sc = y;
push_heap(h, h + cnt);
}
}
}

int main()
{
n = get(); m = get(); src = get();
while (m--) addEdge(get(), get(), get());
Dijkstra(src);
for (int i = 1; i <= n; ++i) put(dis[i]), putchar(' ');
}


【代码2】手写堆

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;
const int N = 1e4 + 5, M = 5e5 + 5;
int dis
, n, m, src; bool vis
;

inline int get()
{
char ch; int res = 0;
while ((ch = getchar()) < '0' || ch > '9');
res = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9')
res = (res << 3) + (res << 1) + ch - '0';
return res;
}

inline void put(int x)
{
if (x > 9) put(x / 10);
putchar(x % 10 + 48);
}

struct Edge
{
int to, cst; Edge *nxt;
}a[M], *T = a, *lst
;

struct point
{
int s, t;
inline bool operator < (const point &x)
{
return s < x.s;
}
point() {}
point(const int &S, const int &T):
s(S), t(T) {}
};

struct SmaRt
{
point g[M];  int len;

inline void Pop()
{
g[1] = g[len--];
int now = 1, nxt = 2; point res = g[1];
while (nxt <= len)
{
if (nxt < len && g[nxt | 1] < g[nxt]) nxt |= 1;
if (g[nxt] < res)
g[now] = g[nxt], nxt = (now = nxt) << 1;
else break;
}
g[now] = res;
}

inline void Push(point res)
{
g[++len] = res;
int now = len, nxt = len >> 1;
while (nxt)
{
if (res < g[nxt])
g[now] = g[nxt], nxt = (now = nxt) >> 1;
else break;
}
g[now] = res;
}
}Q;

inline void addEdge(const int &x, const int &y, const int &z)
{
(++T)->nxt = lst[x]; lst[x] = T; T->to = y; T->cst = z;
}

inline void Dijkstra(const int &st)
{
for (int i = 1; i <= n; ++i) dis[i] = 2147483647;
dis[st] = 0; Q.Push(point(0, st)); int x, y;
for (int i = 1; i <= n; ++i)
{
while (Q.len && vis[Q.g[1].t]) Q.Pop();
if (!Q.len) break;
vis[x = Q.g[1].t] = true; Q.Pop();
for (Edge *e = lst[x]; e; e = e->nxt)
if (dis[y = e->to] > dis[x] + e->cst)
dis[y] = dis[x] + e->cst, Q.Push(point(dis[y], y));
}
}

int main()
{
n = get(); m = get(); src = get(); int x, y, z;
while (m--)
{
x = get(); y = get(); z = get();
addEdge(x, y, z);
}
Dijkstra(src);
for (int i = 1; i <= n; ++i) put(dis[i]), putchar(' ');
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dijkstra