洛谷P3371、P4779 最短路Dijikstra优化历程
两个题目链接:
洛谷P3379:基础数据:用邻接表或链式前向星即可过掉。(点数规模超过10e4=>邻接表,一般用临街矩阵的都是规模在100)
洛谷P4779:数据进行增强:需要邻接表和链式前向星优化空间+堆优化提高效率
背景:近来在洛谷刷题 (Aczy156的首页 ),碰到这个题比较麻烦,一开始用邻接矩阵直接MLE了三个点,其他全wa,后来看了题解需要邻接表。后来在学LCA的时候有学到图的新的表示方法-链式前向星(博主在个人blog中整理的 Algorithm14.0 图论 图的四种常用的存储形式 ,
顺便引引流,当然还有整理的一些其他算法的相关博客),然后又扭头回来重写了一遍,基础数据a了,但是P4779数据增强又t了。。。真是命运多舛,又接(看)着(看)学(题)习(解),发现需要用堆优化。。。
然后就过来写了个blog。
邻接矩阵 直接MLE
#include <iostream>
using namespace std;
#define maxn 10010
typedef long long ll;
ll n, m, bg, dis[maxn], vis[maxn], mp[maxn][maxn], ta, tb, tc, tem, v;
const int INF = (1<<31)-1;
void dijkstra(){
for (int i = 1; i <= n; ++i) dis[i] = mp[bg][i];
vis[bg] = 1;vis[bg] = 1;
for (int i = 1; i <= n; ++i) {
tem = INF,v = bg;
for (int j = 1; j <= n; ++j) if (!vis[j] && dis[j] <= tem) tem = dis[v=j];
vis[v] = 1;
for (int j = 1; j <= n; ++j) if (!vis[j] && dis[j] > dis[v]+mp[v][j]) dis[j] = dis[v]+mp[v][j];
}
for (int i = 1; i <= n; ++i) printf("%lld ", dis[i]);
}
int main() {
scanf("%lld%lld%lld", &n, &m, &bg);
for (int i = 0; i < m; ++i) {
scanf("%lld%lld%lld", &ta, &tb, &tc);
mp[ta][tb] = mp[tb][ta] = tc;
}
dijkstra();
return 0;
}
一开始MLE了3个,wa了7个,以为代码有问题,后来前前后后改了好几遍
邻接表(P3379的AC代码)
#include <iostream>
using namespace std;
#define maxn 50010
int n, m, bg, dis[maxn], vis[maxn], ta, tb, tc, tem, v;
#include <vector>
struct edge{
int to, cost;
};
vector<edge> gh[maxn];
const int INF = 2147483647;
void dijkstra() {
for (int i = 1; i <= n; ++i) dis[i] = INF;
dis[bg] = 0;
for (int i = 1; i <= n; ++i) {
tem = INF, v = bg;
for (int j = 1; j <= n; ++j) if (!vis[j] && dis[j] < tem) tem = dis[v=j];
vis[v] = 1;
for (int j = 0; j < gh[v].size(); ++j) {
int tg = gh[v][j].to;
if (!vis[tg] && dis[tg] > dis[v]+gh[v][j].cost) dis[tg]=dis[v]+gh[v][j].cost;
}
}
for (int i = 1; i <= n; ++i) printf("%d ", dis[i]);
}
int main() {
scanf("%d%d%d", &n, &m, &bg);
for (int i = 0; i < m; ++i) {
edge teme;
scanf("%d%d%d", &ta, &teme.to, &teme.cost);
gh[ta].push_back(teme);
}
dijkstra();
return 0;
}
A掉基础数据了
堆优化(P4779的AC代码)
后来扭头回来写了链式前向星的,交了一发数据增强之后的P4779,结果全t了
然后发现题解中需要进行堆优化来提高速度
最终通过优先队列来存放node,重载运算符让边权小的(dis)排在前面,然后每次提取堆顶,即可。(用链式前向星存储图)
#include <iostream>
using namespace std;
#define maxpoint 100010
#define maxedge 200010
#define INF 2147483647
int n, m, s, ta, tb, tc, dis[maxpoint], vis[maxpoint], v, tem=INF;
struct node {
int to, next, cost;
}edge[maxedge]; int head[maxpoint], tot;
#include <queue>
struct nd {
int dis, pos;
nd(int dis, int pos): dis(dis), pos(pos) {}
bool operator < (const nd n) const {return dis > n.dis;}
};
priority_queue<nd> pq;
void addedge(int from, int to, int cost) {
edge[++tot].to = to;
edge[tot].next = head[from];
edge[tot].cost = cost;
head[from] = tot;
}
/*
* 堆优化
*/
void dijkstra() {
for (int i = 1; i <= n; ++i) dis[i] = INF;
dis[s] = 0;
pq.push(nd(0, s));
while (!pq.empty()) {
nd nw = pq.top();pq.pop();
int from = nw.pos;
if (!vis[from]) {
vis[from] = 1;
for (int i = head[from]; i; i=edge[i].next) {
int to = edge[i].to;
if (dis[to] > dis[from]+edge[i].cost) {
dis[to] = dis[from]+edge[i].cost;
if (!vis[to]) pq.push(nd(dis[to], to));
}
}
}
}
for (int i = 1; i <= n; ++i) printf("%d ", dis[i]);
}
/*
* 非堆优化
*/
//void dijkstra() {
// for (int i = 1; i <= n; ++i) dis[i] = INF;
// dis[s] = 0;
// for (int i = 1; i <= n; ++i) {
// tem = INF;v = s;
// for (int j = 1; j <= n; ++j) if (!vis[j] && dis[j] < tem) tem = dis[v=j];
// vis[v] = 1;
// for (int j = head[v]; j; j=edge[j].next) {
// int to = edge[j].to;
// if (!vis[to] && dis[to] > dis[v]+edge[j].cost) dis[to] = dis[v]+edge[j].cost;
// }
// }
// for (int i = 1; i <= n; ++i) printf("%d ", dis[i]);
//}
int main() {
scanf("%d%d%d", &n, &m, &s);
for (int i = 1; i <= m; ++i) {
scanf("%d%d%d", &ta, &tb, &tc);
addedge(ta, tb, tc);
}
dijkstra();
return 0;
}