图的问题中许多是关于最短路径的,这个问题情况又分为几种,这篇就我遇到过的三种情况分类讲一下,算法的解释我没有写的太详细,算法书和其他博文里面有很多。
1.有一种最简单的情况,就是图的各个边的权值相等,这时我们以起点进行广度优先搜索终点,就可以最终得到最短距离。
题目:
Description
给定一个无向图,用0,1,2,...,n-1代表其n个顶点,求指定两个顶点之间的最短距离。
Input
第一行为测试样例总数;
之后是N个测试样例,每个测试样例的第一行为4个数:顶点个数n,边数m, 顶点v1, 顶点v2。
n m v1 v2
之后是m行数对,每个数对<s,t>表示顶点s与顶点t之间存在边。
Output
对于每个样例,用单独一行输出最短距离。
Sample Input
2 3 2 2 1 0 1 0 2 4 4 0 2 0 1 1 3 2 3 3 0
Sample Output
2 2
#include<iostream>
#include<queue>
using namespace std;
int main() {
int num;
cin >> num;
while (num--){
int dis[100];
bool is[100] = {};
bool graph[100][100] = {};
int vertex, edge, a, b;
cin >> vertex >> edge >> a >> b;
dis[a] = 0;
queue<int> tem;
tem.push(a);
int p, q;
for (int i = 0; i < edge; i++) {
cin >> p >> q;
graph[p][q] = true;
graph[q][p] = true;
}
while (!tem.empty()) {
int tar = tem.front();
tem.pop();
for (int i = 0; i < vertex; i++) {
if (graph[tar][i] && is[i] == false) {
dis[i] = dis[tar] + 1;
is[i] = true;
tem.push(i);
}
}
}
cout << dis[b] << endl;
}
}
2.Dijkstra:当上述情况有变,边的权值不再相等时,这时可以使用Dijstra算法,最终的结果也是可以得到从一个顶点出发到剩余点的最短路径,当然如果你只想得到起点到终点的最短路径,和第一种情况一样,可以在找到终点时就退出循环停止寻找。
我的代码是用stl中的set实现的,也可以用一个bool visited[]同样实现,我的代码中path[]记录了最短路径:
void findshortest(int s, int e) {
int path[15][15];
int shortest[15];
for (int i = 1; i < 12; i ++) {
shortest[i] = distancee[s][i];
for (int j = 1; j < 12; j++) {
path[i][j] = -1;
}
}
set<int> ready;
set<int> notready;
ready.insert(s);
for (int i = 1; i < 12; i++) {
if (i != s) notready.insert(i);
}
int po = -1;
int di = 4000;
set<int>::iterator iter;
set<int>::iterator it;
while (po != e) {
di = 4000;
for (iter = notready.begin(); iter != notready.end(); iter++) {
for (it = ready.begin(); it != ready.end(); it++) {
if (distancee[*iter][*it] != -1) {
if (shortest[*iter] == -1) {
shortest[*iter] = distancee[*iter][*it] + shortest[*it];
int i = 1;
while(path[*it][i] != -1) {
path[*iter][i] = path[*it][i];
i++;
}
path[*iter][i] = *it;
path[*iter][i+1] = -1;
} else {
if (shortest[*iter] > distancee[*iter][*it] + shortest[*it]) {
int i = 1;
while(path[*it][i] != -1) {
path[*iter][i] = path[*it][i];
i++;
}
path[*iter][i] = *it;
path[*iter][i+1] = -1;
shortest[*iter] = distancee[*iter][*it] + shortest[*it];
}
}
}
}
}
for (iter = notready.begin(); iter != notready.end(); iter++) {
if (shortest[*iter] < di && shortest[*iter] != -1) {
di = shortest[*iter];
po = *iter;
}
}
notready.erase(po);
ready.insert(po);
}
}
3.Floyd-Warshall :前两种方法都是单源的,也就是适用于寻找一个顶点出发到其他所有顶点的最短路径,而如果想求解多源,那么会很麻烦,这时Floyd-Warshall以O(n^3)的时间复杂度就能完成这件事情,得到所有点之间的最短路径。
//temp[][]是邻接矩阵,num是vertex的数量
void Floyd() {
for (int k = 0; k < num; k++) {
for (int i = 0; i < num; i++){
for (int j = 0; j < num; j++) {
if (temp[i][j] > temp[i][k] + temp[k][j]) temp[i][j] = temp[i][k] + temp[k][j];
}
}
}
}
//得到的temp就是最短路径矩阵了
当时间复杂度要求不高的情况下,Floyd算法当然也可以用于前2种情况,还会使得代码量减少。