想练一练dijkstra+堆优化,从来没有写过~
要看懂以下内容 首先自学 dijkstra 算法, 和 堆哦~
一开始考虑是想堆里存结构体,但是经过潘神指导,发现不需要~毕竟写结构体会蛋疼些。。
介绍一下各个数组的作用
d[i] 表示 从源点 s 到 节点 i 的当前最短距离
v[i] 其实和 d[i] 是一个东西,也是源点 s 到 节点 i 的当前最短距离, 唯一的不同是 当一个节点 i 已经被确认为最短路径的点 后, v[i] = inf, 这样在下次取堆的最小元素的时候,就不会取到已经拓展完毕的点。
简单来说 就是 堆的维护 用 v[i] 而不是 d[i], 而最终答案存在 d[i] 里。
heap[i] 表示 堆里的 第 i 个 元素 是 实际的 哪个节点。(堆到图中点的映射)
pos[i] 表示 实际的节点 i 是堆里的哪个元素 (图中点到堆的映射)
end, first, cost, next 都是基本的邻接表的数组。(比较喜欢用数组而不是指针~)
这样的话 思路就比较清晰了,代码不长,也很容易懂。
这里我用 USACO 3.2.6 Sweet Butter 作为例题,实现 dijstra+堆优化(其实这题用 SPFA 很容易过。。)
/*
PROG:butter
LANG:C++
*/
#include <cstdio>
#include <algorithm>
using namespace std;
const int inf = ~0U>>1;
const int MAXN = 1000, MAXM = 3000;
int end[MAXM], first[MAXN], cost[MAXM], next[MAXM];
int d[MAXN], v[MAXN], heap[MAXN], pos[MAXN], cow[501];
int n, p, c, tot, ans=inf, dist[501][MAXN];
void ins(int x, int y, int z)
{
end[++tot] = y, cost[tot] = z;
next[tot] = first[x], first[x] = tot;
}
void Swap(int i, int j)
{
swap(pos[heap[i]], pos[heap[j]]); // 将 图中点 映射到 堆中的位置 交换
swap(heap[i], heap[j]); // 将 堆中元素 映射到的 图中点 交换
}
void pushUp(int x) // 向上维护
{
for ( ;x != 1 && v[heap[x]] < v[heap[x>>1]];x >>= 1)
Swap(x, x>>1);
}
void pushDown(int x) // 向下维护
{
for (x += x; x <= p; x += x)
{
if (x+1 <= p && v[heap[x]] > v[heap[x+1]]) ++x;
if (v[heap[x>>1]] > v[heap[x]]) Swap(x, x>>1);
}
}
void update(int x, int value) // 更新节点距离,注意是使用 v[i]
{
v[x] = value;
pushUp(pos[x]);
pushDown(pos[x]);
}
void dijkstra(int s)
{
for (int i = 1;i <= p;++i)
{
heap[i] = pos[i] = i; // 初始化映射
d[i] = v[i] = inf; // 初始化距离
}
d[s] = 0;
update(s, 0);
for (int i = 0;i < p;++i)
{
int tmp = heap[1];
for (int k = first[tmp]; k ; k = next[k])
{
if (cost[k]+d[tmp] < d[end[k]])
{
d[end[k]] = cost[k]+d[tmp];
update(end[k], d[end[k]]);
}
}
update(tmp, inf); // 拓展完后,将该节点在堆中的值改为 inf
}
}
int main()
{
freopen("butter.in", "r", stdin);
freopen("butter.out", "w", stdout);
int x, y, z;
scanf("%d%d%d", &n, &p, &c);
for (int i = 1;i <= n;++i) scanf("%d", &cow[i]);
for (int i = 1;i <= c;++i)
{
scanf("%d%d%d", &x, &y, &z);
ins(x, y, z);
ins(y, x, z);
}
for (int i = 1;i <= n;++i)
{
dijkstra(cow[i]);
for (int j = 1;j <= p;++j) dist[i][j] = d[j];
}
for (int i = 1;i <= p;++i)
{
int tmp = 0;
for (int j = 1;j <= n;++j) tmp += dist[j][i];
if (tmp < ans) ans = tmp;
}
printf("%d\n", ans);
}