# Dijkstra

Dijkstra算法是图论中用来求单源最短路径的经典算法，复杂度可以优化到 O ( m l o g ( n ) ) O(mlog(n)) 。从整体上看就是从一个起点，扩散到整个图的过程。

# 原理

Dijkstra算法应用了贪心的思想，即“抄近路走”。维护两个集合 A A B B A A 表示已确定最短路径的结点集（红色表示）， B B 表示邻居结点（蓝色表示）。

1. 首先把起点1放入 A A 中，把它的所有邻居放入 B B

2. B B 中找距离起点最短的结点放入 A A 中，即结点3，并把它的邻居加入进 B B ，距离是起点到该节点的距离+该节点到邻居的距离。

3. 此时 B B 中存在相同结点2，我们取距离更短的那个，即舍弃(2,5)

4. 以此类推，把 B B 中距离最短的结点2放入 A A 中，加入邻居，然后舍弃更远的(4,7)

5. 最后得到起点到其他结点的最短路径

上述方法中，对于每次寻找 B B 中距离最近结点，可以用优先队列实现，这样依赖复杂度就能优化到 O ( m l o g ( n ) ) O(mlog(n))
如果要打印路径，定义一个数组 p r e [ ] pre[] 记录前驱结点就好了，也就是它是作为谁的邻居进入 B B 中的，然后递归打印。

# 模板

struct edge {  //边
int from, to, w;  //起点，终点，权值
edge(int a, int b, int c) {
from = a, to = b, w = c;
}
};
struct node {
int id, dis; //即图解中的(结点，距离)
node(int a, int b) {
id = a, dis = b;
}
bool operator< (const node &a)const {
return a.dis < dis;
}
};
int n, m, x, y, z;
vector<edge>e[maxn];  //邻接表存图
int dis[maxn], pre[maxn]; //记录最短路径和 前驱节点
bool vis[maxn];  //记录是否已入A，实现舍弃操作
void print_path(int s, int t) { //打印起点s到点t最短路径
if (s == t)return;
print_path(s, pre[t]);
printf("%d ", t);
}
void dijkstra(int s) { //传入起点
memset(dis, inf, sizeof(dis));
memset(vis, false, sizeof(vis));
dis[s] = 0;
priority_queue<node>q;  //优先队列
q.push(node(s, dis[s]));  //入队起点
while (!q.empty()) {
node cur = q.top();
q.pop();
if (vis[cur.id])continue;
vis[cur.id] = true;  //即已找到最短路径
for (int i = 0; i < e[cur.id].size(); i++) {  //检查所有邻居
edge nex = e[cur.id][i];
if (vis[nex.to])continue;  //舍弃(更优的已经get)
if (dis[nex.to] > nex.w + cur.dis) { //扩展新邻居
dis[nex.to] = nex.w + cur.dis;
q.push(node(nex.to, dis[nex.to]));
//pre[nex.to] = cur.id;  //记录路径
}
}
}
}


# 例题

## HDU-2544 最短路

HDU-2544 最短路

Problem Description

Input

Output

Sample Input
2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0
Sample Output
3
2

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
const int maxn = 102;
struct edge {
int from, to, w;
edge(int a, int b, int c) {
from = a, to = b, w = c;
}
};
struct node {
int id, dis;
node(int a, int b) {
id = a, dis = b;
}
bool operator< (const node &a)const {
return a.dis < dis;
}
};
int n, m, x, y, z;
vector<edge>e[maxn];
int dis[maxn];
bool vis[maxn];
void dijkstra(int s) {
dis[s] = 0;
priority_queue<node>q;
q.push(node(s, dis[s]));
while (!q.empty()) {
node cur = q.top();
q.pop();
if (vis[cur.id])continue;
vis[cur.id] = true;
for (int i = 0; i < e[cur.id].size(); i++) {
edge nex = e[cur.id][i];
if (vis[nex.to])continue;
if (dis[nex.to] > nex.w + cur.dis) {
dis[nex.to] = nex.w + cur.dis;
q.push(node(nex.to, dis[nex.to]));
}
}
}
}
int main() {
while (~scanf("%d%d", &n, &m)) {
if (n == 0 && m == 0)break;
for (int i = 1; i <= n; i++)e[i].clear();
memset(dis, inf, sizeof(dis));
memset(vis, false, sizeof(vis));
while (m--) {
scanf("%d%d%d", &x, &y, &z);
e[x].push_back(edge(x, y, z));
e[y].push_back(edge(y, x, z));
}
dijkstra(1);
printf("%d\n", dis[n]);
}
return 0;
}


## HDU-2680 Choose the best route

HDU-2680 Choose the best route

Problem Description
One day , Kiki wants to visit one of her friends. As she is liable to carsickness , she wants to arrive at her friend’s home as soon as possible . Now give you a map of the city’s traffic route, and the stations which are near Kiki’s home so that she can take. You may suppose Kiki can change the bus at any station. Please find out the least time Kiki needs to spend. To make it easy, if the city have n bus stations ,the stations will been expressed as an integer 1,2,3…n.
Input
There are several test cases.
Each case begins with three integers n, m and s,(n<1000,m<20000,1=<s<=n) n stands for the number of bus stations in this city and m stands for the number of directed ways between bus stations .(Maybe there are several ways between two bus stations .) s stands for the bus station that near Kiki’s friend’s home.
Then follow m lines ,each line contains three integers p , q , t (0<t<=1000). means from station p to station q there is a way and it will costs t minutes .
Then a line with an integer w(0<w<n), means the number of stations Kiki can take at the beginning. Then follows w integers stands for these stations.
Output
The output contains one line for each data set : the least time Kiki needs to spend ,if it’s impossible to find such a route ,just output “-1”.
Sample Input
5 8 5
1 2 2
1 5 3
1 3 4
2 4 7
2 5 6
2 3 5
3 5 1
4 5 1
2
2 3
4 3 4
1 2 3
1 3 4
2 3 2
1
1
Sample Output
1
-1

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
const int maxn = 1003;
struct node {
int id, dis;
node(int a, int b) {
id = a, dis = b;
}
bool operator <(const node& a)const {
return a.dis < dis;
}
};
int mp[maxn][maxn], dis[maxn];
bool vis[maxn];
int n, m, e, x, y, z;
void dijkstra() {
dis[0] = 0;
priority_queue<node>q;
q.push(node(0, dis[0]));
while (!q.empty()) {
node cur = q.top();
q.pop();
if (vis[cur.id])continue;
vis[cur.id] = true;
for (int i = 0; i <= n; i++) {
if (mp[cur.id][i] == inf)continue; //无路
if (vis[i])continue;
if (dis[i] > mp[cur.id][i] + cur.dis) {
dis[i] = mp[cur.id][i] + cur.dis;
q.push(node(i, dis[i]));
}
}
}
}
int main() {
while (~scanf("%d%d%d", &n, &m, &e)) {
memset(mp, inf, sizeof(mp));
memset(dis, inf, sizeof(dis));
memset(vis, false, sizeof(vis));
while (m--) {
scanf("%d%d%d", &x, &y, &z);
if (z < mp[x][y])  //重边
mp[x][y] = z;
}
scanf("%d", &x);
while (x--) { //置距起点为0
scanf("%d", &y);
mp[0][y] = 0;
}
dijkstra();
if (dis[e] == inf)puts("-1");
else printf("%d\n", dis[e]);
}
return 0;
}


## POJ-1062 昂贵的聘礼

POJ-1062 昂贵的聘礼

Problem Description

Input

Output

Sample Input
1 4
10000 3 2
2 8000
3 5000
1000 2 1
4 200
3000 2 1
4 200
50 2 0
Sample Output
5250

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f
const int maxn = 102;
struct node {
int id, dis;
node(int a, int b) {
id = a, dis = b;
}
bool operator<(const node& a)const {
return a.dis < dis;
}
};
int n, m, x, y, z;
int mp[maxn][maxn], dis[maxn];
int lev[maxn], val[maxn];
bool tag[maxn], vis[maxn];
int dijkstra() {
memset(vis, false, sizeof(vis));
memset(dis, inf, sizeof(dis));
priority_queue<node>q;
dis[1] = 0;
q.push(node(1, dis[1]));
while (!q.empty()) {
node cur = q.top();
q.pop();
if (vis[cur.id])continue;
vis[cur.id] = true;
for (int i = 1; i <= n; i++) {
if (vis[i] || !tag[i])continue; //多一个判断：是否在枚举区间内
if (dis[i] > mp[cur.id][i] + cur.dis) {
dis[i] = mp[cur.id][i] + cur.dis;
q.push(node(i, dis[i]));
}
}
}
int rtn = inf;
for (int i = 1; i <= n; i++)
if (rtn > dis[i] + val[i])  //记得加上结点权值
rtn = dis[i] + val[i];
return rtn;
}
int main() {
scanf("%d%d", &m, &n);
memset(mp, inf, sizeof(mp));
for (int i = 1; i <= n; i++) {
scanf("%d%d%d", &val[i], &lev[i], &x);
while (x--) {
scanf("%d%d", &y, &z);
mp[i][y] = z;
}
}
int ans = inf;
for (int i = 0; i <= m; i++) {
memset(tag, false, sizeof(tag));
for (int j = 1; j <= n; j++) {  //枚举
if (lev[1] - m + i <= lev[j] && lev[1] + i >= lev[j])
tag[j] = true;
}
ans = min(ans, dijkstra());
}
printf("%d\n", ans);
return 0;
}


## POJ-1511 Invitation Cards

POJ-1511 Invitation Cards

Problem Description
In the age of television, not many people attend theater performances. Antique Comedians of Malidinesia are aware of this fact. They want to propagate theater and, most of all, Antique Comedies. They have printed invitation cards with all the necessary information and with the programme. A lot of students were hired to distribute these invitations among the people. Each student volunteer has assigned exactly one bus stop and he or she stays there the whole day and gives invitation to people travelling by bus. A special course was taken where students learned how to influence people and what is the difference between influencing and robbery.
The transport system is very special: all lines are unidirectional and connect exactly two stops. Buses leave the originating stop with passangers each half an hour. After reaching the destination stop they return empty to the originating stop, where they wait until the next full half an hour, e.g. X:00 or X:30, where ‘X’ denotes the hour. The fee for transport between two stops is given by special tables and is payable on the spot. The lines are planned in such a way, that each round trip (i.e. a journey starting and finishing at the same stop) passes through a Central Checkpoint Stop (CCS) where each passenger has to pass a thorough check including body scan.
All the ACM student members leave the CCS each morning. Each volunteer is to move to one predetermined stop to invite passengers. There are as many volunteers as stops. At the end of the day, all students travel back to CCS. You are to write a computer program that helps ACM to minimize the amount of money to pay every day for the transport of their employees.
Input
The input consists of N cases. The first line of the input contains only positive integer N. Then follow the cases. Each case begins with a line containing exactly two integers P and Q, 1 <= P,Q <= 1000000. P is the number of stops including CCS and Q the number of bus lines. Then there are Q lines, each describing one bus line. Each of the lines contains exactly three numbers - the originating stop, the destination stop and the price. The CCS is designated by number 1. Prices are positive integers the sum of which is smaller than 1000000000. You can also assume it is always possible to get from any stop to any other stop.
Output
For each case, print one line containing the minimum amount of money to be paid each day by ACM for the travel costs of its volunteers.
Sample Input
2
2 2
1 2 13
2 1 33
4 6
1 2 10
2 1 60
1 3 20
3 4 10
2 4 5
4 1 50
Sample Output
46
210

n站点m条公交路线，只从起点到终点(单向)，求往返最小花费，来回往返两次，把来的单向路弄一次，再把路反过来弄一次就行了。

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;
const int maxn = 1000006;
struct node {
int id, dis;
node(int a, int b) {
id = a, dis = b;
}
bool operator<(const node& a)const {
return a.dis < dis;
}
};
struct edge {
int from, to, w;
edge(int a, int b, int c) {
from = a, to = b, w = c;
}
};
vector<edge>e[maxn];
int t, n, m;
int dis[maxn];
int from[maxn], to[maxn], cost[maxn];
bool vis[maxn];
void dijkstra(int s) {
memset(dis, inf, sizeof(dis));
memset(vis, false, sizeof(vis));
dis[s] = 0;
priority_queue<node>q;
q.push(node(s, dis[s]));
while (!q.empty()) {
node cur = q.top();
q.pop();
if (vis[cur.id])continue;
vis[cur.id] = true;
for (int i = 0; i < e[cur.id].size(); i++) {
edge nex = e[cur.id][i];
if (vis[nex.to])continue;
if (dis[nex.to] > cur.dis + nex.w) {
dis[nex.to] = cur.dis + nex.w;
q.push(node(nex.to, dis[nex.to]));
}
}
}
}
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
for (int i = 0; i <= n; i++)e[i].clear();
for (int i = 0; i < m; i++) {
scanf("%d%d%d", &from[i], &to[i], &cost[i]);
e[from[i]].push_back(edge(from[i], to[i], cost[i]));
}
dijkstra(1);
ll ans = 0;
for (int i = 1; i <= n; i++)
ans += dis[i];
for (int i = 0; i <= n; i++)e[i].clear();
for (int i = 0; i < m; i++) //反转路的方向
e[to[i]].push_back(edge(to[i], from[i], cost[i]));
dijkstra(1);
for (int i = 1; i <= n; i++)
ans += dis[i];
printf("%lld\n", ans);
}
return 0;
}


12-05

07-11 700
03-26 251
02-16 189
05-03 263
08-04 1万+
07-08 436
03-09
12-09 832
06-03 33
07-03 272
11-15 778
02-25 2万+