我以前和你一样也是个vectorer,直到我膝盖中了一TLE.
Invitation Cards 这道题目,8s的时限,1e6的数据,只不过是跑了两边DIjkstra,vector超时,而向前星只需要2s.
同样是邻接表存图,链式向前星虽然没有vector那么简洁,但是速度会有明显提升,并且许多操作两者是有共同写法的,有必要学一下.
使用链式向前星存图:
// N - 节点数, M - 边数 struct E{ int to, wei, nxt; // nxt即next, 但后者似乎是保留名称 }e[M]; int head[N], ind = 1; // 下面添加一条由x指向y, 权为w的有向边 inline void add(int x, int y, int w){ e[ind].to = y; e[ind].wei = w; e[ind].nxt = head[x]; head[x] = ind++; }
读取图上信息:
// 遍历以x为起点的所有边 for(int i = head[cur.to]; i; i = e[i].nxt){ // e[i].to - 当前边指向的终点 // e[i].wei - 当前边的权 // ...operations... }
给出一道单源最短路径的模板题,数据范围达到了3e6.
这里用链式向前星写一个Dijkstra,我的实现方法除了建图与读图部分外与vector版本基本相同.
#include <algorithm> #include <cstdio> #include <cstring> #include <iostream> #include <queue> using namespace std; struct E{ int to, wei, nxt; }e[150010]; struct Q{ // queue_element int to, wei; bool operator<(const Q &other)const {return wei > other.wei;} }; priority_queue<Q> q; int n, m, head[30010], ind = 1, dist[30010]; inline void add(int x, int y, int w){ e[ind].to = y; e[ind].wei = w; e[ind].nxt = head[x]; head[x] = ind++; } int main(){ memset(dist, -1, sizeof(dist)); scanf("%d%d", &n, &m); while(m--){ int a, b, c; scanf("%d%d%d", &a, &b, &c); add(a, b, c); } q.push({1, 0}); while(!q.empty()){ Q cur = q.top(); q.pop(); if(dist[cur.to] != -1) continue; dist[cur.to] = cur.wei; for(int i = head[cur.to]; i; i = e[i].nxt) if(dist[e[i].to] == -1) q.push({e[i].to, cur.wei + e[i].wei}); } printf("%d ", dist[n] - dist[1]); return 0; }
(后两个是时间(ms)和空间(MB))
再给出一份我写的vector版本供参考.
可以说是非常落魄了,只有加了快读后才能通过.
#include <algorithm> #include <cstdio> #include <cstring> #include <iostream> #include <queue> #include <vector> using namespace std; struct E{ // 这里E和Q可以通用 int to, wei; bool operator<(const E& other) const {return wei > other.wei;} }; vector<E> e[30010]; priority_queue<E> q; int n, m, dist[30010]; inline int read() { char ch = getchar(); int x = 0, f = 1; while (ch > '9' || ch < '0') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } int main(){ memset(dist, -1, sizeof(dist)); n = read(), m = read(); while(m--){ int a, b, c; a = read(), b = read(), c = read(); e[a].push_back({b, c}); } q.push({1, 0}); while(!q.empty()){ E cur = q.top(); q.pop(); if(dist[cur.to] != -1) continue; dist[cur.to] = cur.wei; for(vector<E>::iterator i = e[cur.to].begin(); i != e[cur.to].end(); i++) if(dist[i->to] == -1) q.push({i->to, cur.wei + i->wei}); } printf("%d ", dist[n] - dist[1]); return 0; }
并且性能相比于链式向前星几乎是腰斩.