1. 程式人生 > >最短路板子第一彈·Dijkstra基礎

最短路板子第一彈·Dijkstra基礎

1. Dijkstra

無圖警告

1.1 思路

  Dijkstra的來歷不必多講,但是需要知道的,是Dijkstra是一種基於“貪心“的求“單源最短路”演算法,和最小生成樹中的Prim是類似的。(如果你不知道什麼是單源最短路,建議百度一下再來)

  粗略來講,Dijkstra的做法就是:

以起始點為中心向外層層擴充套件,直到擴充套件到終點為止 ——百度百科

  既然是這樣,我們的鬆弛操作就該登場了

1.2 最短路的靈魂——鬆弛

  何謂鬆弛?簡單講,一根變成兩根,它不就鬆了嗎?也就是說,把一條邊用幾條比它更短的邊來替代,就是鬆弛了。

  於是就出現了諸如這樣的程式碼塊:

if(d[i] > d[j] + w[i, j])

{

	d[i] = d[j] + w[i, j];

}

  這裡的d[i]d[i]代表ii點到出發點的最短距離,即答案。

  這裡的w[i,j]w[i, j]代表ii點到jj點的已經存在的路徑的長度,就是讀進來的那個,先用鄰接矩陣存著。

Ps:如果你剛剛學,建議在這裡停下來用至少5分鐘“用心”想想為什麼,可以畫畫圖,查查相關資料(比如別人的Blog)。真正的學懂,一定是理解,能夠自己推出來,而不是單純的記憶。

1.3 完整程式碼+註釋

相信理解過以上兩點的基本上就懂了,所以就不多解釋了。(逃

不過啊,前方大量註釋預警:(程式碼就忍著點看吧qwq)

#include<bits/stdc++.h>
using namespace std;
typedef double dd;
typedef long long ll;
#define fora(i, j, k) for(int i = j; i <= k; ++i)
#define forb(i, j, k) for(int i = j; i >= k; --i)
#define Set(a, b) memset(a, b, sizeof(a))
inline ll lax(ll x, ll y) {return x > y ? x : y;}
inline ll lin(ll x, ll y) {return x < y ? x : y;}
inline ll read()
{
	char c = getchar(); ll s = 0; int tip = 1;
	for(; c < '0' || c > '9'; c = getchar()) if(c == '-') tip = -1;
	for(; c >= '0' && c <= '9'; c = getchar()) s = s * 10 + c - '0';
	return s * tip;
}
//從這裡開始看就好,上面都是板子。
const int maxn = 10000 + 10;
const int maxm = 500000 + 10;
const int INf = 2147483647;

int i, j, k, m, n, mind, t;
int a[maxm], b[maxm], c[maxm], u[maxn], v[maxm], d[maxn];
bool book[maxn];

void file()
{
	freopen("dijkstra.in", "r", stdin);
	freopen("dijkstra.out", "w", stdout);
}

void init()
{
	n = read(), m = read(), k = read();
	fora(i, 1, m)
	{
		a[i] = read(), b[i] = read(), c[i] = read();
		v[i] = u[a[i]], u[a[i]] = i;
	}
	fora(i, 1, n) if(i != k) d[i] = INf;
}

void work()

{
	fora(i, 1, n)
	{
		mind = INf, t = 0;
		fora(j, 1, n) if(book[j] == 0 && d[j] < mind) mind = d[j], t = j;
		book[t] ^= 1; int j = u[t];
		for(; j != 0; j = v[j]) if(book[b[j]] == 0 && d[b[j]] > d[t] + c[j]) d[b[j]] = d[t] + c[j];
	}
}

void write()
{
	fora(i, 1, n) printf("%d ", d[i]);
    cout << endl;
}

int main()
{
//	file();
	init(); //初始化部分
	work(); //主要操作部分
	write(); //輸出部分
	return 0; //沒了
}

看完以後就關上它,自己寫一遍,交到各大評測網站上吧! 傳送門來著的