【Dijkstra模板】codeforces715B Complete The Graph(最短路径)
记录一下Dijkstra的模板,主要加了一个优先队列,时间复杂度变成O(mlogn),速度快了很多。
struct Edge
{
int from, to, dist;
Edge(int u, int v, int w) :from(u), to(v), dist(w) {}
};
struct HeapNode
{
int d, u;
HeapNode(int x, int y) :d(x), u(y) {}
bool operator<(const HeapNode &rhs) const
{
return d > rhs.d;
}
};
struct Dijkstra
{
vector<Edge> edges; //边保存
vector<int> G[maxn]; //保存每个点能到达的所有边
bool done[maxn]; //是否已经永久标记
int d[maxn]; //起点到各个点的距离
int p[maxn]; //最短路的上一条弧
void init()
{
for (int i = 0; i < maxn; i++)
G[i].clear();
edges.clear();
}
void addedge(int from, int to, int dist)
{
edges.push_back(Edge(from, to, dist));
G[from].push_back(edges.size());
}
void dij()
{
priority_queue<HeapNode> Q;
for (int i = 0; i < n; i++) d[i] = INF;
d[s] = 0;
memset(done, 0, sizeof(done));
Q.push(HeapNode(0,s));
while (!Q.empty())
{
HeapNode x = Q.top(); Q.pop();
int u = x.u;
if (done[u]) continue;
done[u] = true;
for (int i = 0; i < G[u].size(); i++)
{
Edge& e = edges[G[u][i]];
if (d[e.to] > d[u] + e.dist)
{
d[e.to] = d[u] + e.dist;
p[e.to] = G[u][i];
Q.push(HeapNode(d[e.to], e.to));
}
}
}
}
};
下面写一下cf上这道题:
题意:
给出一个无向图,现在要求将所有边权为0的边的权值变成大于等于1的值,问怎么变化使最后的最短路径和为l
要点:
基本就是一个最短路径,题目想起来不难,先把所有权值不为0的图进行一次dij,特判一下。然后将权值为0的边一条一条赋值为1放入图并进行dij,如果此时的最短路径d<=l,那就把这条边改成l - dij()+w即可,剩余所有边改成无穷大。但这题我WA了快10次,主要是输出很烦,而且一开始模板还写错,数组上限也开小了,还是太菜了。
#include<iostream>
#include<cstring>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1005;
const int maxm = 20010;//注意这里
const ll INF = 1000000000000000000;
int n, m, l, s, t, cnt,tot;
int S[maxm], T[maxm];
struct Edge
{
int from, to, dist;
Edge(int u, int v, int w) :from(u), to(v), dist(w) {}
};
struct HeapNode
{
int d, u;
HeapNode(int x, int y) :d(x), u(y) {}
bool operator<(const HeapNode &rhs) const
{
return d > rhs.d;
}
};
struct Dijkstra
{
vector<Edge> edges; //边保存
vector<int> G[maxn]; //保存每个点能到达的所有边
bool done[maxn]; //是否已经永久标记
ll d[maxn]; //起点到各个点的距离
int p[maxn]; //最短路的上一条弧
void init()
{
for (int i = 0; i < maxn; i++)
G[i].clear();
edges.clear();
}
void addedge(int from, int to, int dist)
{
edges.push_back(Edge(from, to, dist));
G[from].push_back(edges.size() - 1);
}
ll dij()
{
priority_queue<HeapNode> Q;
for (int i = 0; i < maxn; i++) d[i] = INF;
d[s] = 0;
memset(done, 0, sizeof(done));
Q.push(HeapNode(0, s));
while (!Q.empty())
{
HeapNode x = Q.top(); Q.pop();
int u = x.u;
if (done[u]) continue;
done[u] = true;
for (int i = 0; i < G[u].size(); i++)
{
Edge& e = edges[G[u][i]];
if (d[e.to] > d[u] + e.dist&&d[u]+e.dist<=l)//这里有个优化
{
d[e.to] = d[u] + e.dist;
p[e.to] = G[u][i];
Q.push(HeapNode(d[e.to], e.to));
}
}
}
return d[t];
}
void print()
{
printf("YES\n");
int t = edges.size();
for (int i = 0; i < t - 2; i += 2)
printf("%d %d %d\n", edges[i].from, edges[i].to, edges[i].dist);
//printf("------------\n");
printf("%d %d %d\n", edges[t - 2].from, edges[t - 2].to, l - dij() + edges[t - 2].dist);
//printf("------------\n");
for (int i = tot; i<=cnt; i++)
printf("%d %d %I64d\n", S[i], T[i], INF);
}
};
Dijkstra graph;
int main()
{
//while (1)
{
scanf("%d%d%d%d%d", &n, &m, &l, &s, &t);
int u, v, w;
graph.init();
for (int i = 0; i < m; i++)
{
scanf("%d%d%d", &u, &v, &w);
if (w)
{
graph.addedge(u, v, w);
graph.addedge(v, u, w);
}
else
{
S[++cnt] = u;
T[cnt] = v;
}
}
tot = 1;
if (graph.dij() < l)//一开始特判
{
//printf("%d\n", graph.dij());
printf("NO\n");
return 0;
}
else if (graph.dij() == l)
{
graph.print();
return 0;
}
for (; tot <= cnt; tot++)//将每个边分别赋值为1加入,如果最短路径小于l就脱出
{
graph.addedge(S[tot], T[tot], 1);
graph.addedge(T[tot], S[tot], 1);
if (graph.dij() <= l)
break;
}
tot++;
//printf("%d %d\n", tot, cnt);
if (tot > cnt + 1)
printf("NO\n");
else
graph.print();
}
return 0;
}