单源最短路径(C++实现)

图的构造

#include 
#include 

using namespace std;

struct edge{
	int to, cost;
};

const int MAX = 1000;

vector G[MAX]; // 图
int V; // 顶点数
int E; // 边数

void creat(){
	// 因为只是支持顶点 0 ~ n, 如果顶点是 1 ~ n, 自行更改 只要把顶点的值减 1 就行了
	// 这里假设是 0 ~ n
	cin >> V >> E;
	for(int i = 0; i < E; ++i){
	    int from, to, cost;
	    cin >> from >> to >> cost;
	    edge e;
	    e.to = to;
	    e.cost = cost;
	    G[from].push_back(e);
	}
}

int main(){
	creat();
	return 0;
}

Dijkstra算法(未经优化)

#include 
#include 

using namespace std;

struct edge{
	int to, cost;
};

const int MAX = 10001;
const int INF = 0x3f3f3f3f; // 假设这是无法到达的话的距离

vector G[MAX]; // 图
int d[MAX];
int used[MAX];
int V; // 顶点数
int E; // 边数
int s; // 出发的点

void creat(){
	// 因为只是支持顶点 0 ~ n, 如果顶点是 1 ~ n, 自行更改 只要把顶点的值减 1 就行了
	// 这里假设是 0 ~ n
	cin >> V >> E >> s;
	for(int i = 0; i < E; ++i){
	    int from, to, cost;
	    cin >> from >> to >> cost;
	    edge e;
	    e.to = to;
	    e.cost = cost;
	    G[from].push_back(e);
	}
}

void Dijkstra(int s){
	fill(d, d + V, INF);
	fill(used, used + V, false);
	d[s] = 0;
	while(true){
	    int v = -1;
	    for(int i = 0; i < V; ++i){
		if(!used[i] && (v == -1 || d[v] > d[i])){ // 寻找到达某一点的最短距离
			v = i;
		}
	    }
	    if(v == -1) break;
	    used[v] = true;
	    for(int i = 0; i < (int)G[v].size(); ++i){
	        edge e = G[v][i];
		if(d[v] != INF) // 如果存在不能到达的点的话,则不予考虑
                d[e.to] = min(d[e.to], d[v] + e.cost); // v -> i 从v到 e.to顶点的距离
	    }
	}
}

void solve(){
	creat();
	Dijkstra(s);
	for(int i = 0; i < V; ++i) cout << d[i] << ' '; // 输出到达各个顶点的最短距离, 如果无法到达结果为 INF
}

int main(){
	solve();
	return 0;
}

Dijkstra(优先队列的优化)

#include 
#include 
#include 
#include 

using namespace std;

struct edge{
	int to, cost;
};

typedef pair P;
const int MAX = 10001;
const int INF = 0x3f3f3f3f; // 假设这是无法到达某一点的距离

vector G[MAX]; // 图
int d[MAX];
int used[MAX];
int V; // 顶点数
int E; // 边数
int s; // 出发的点

void creat(){
	// 因为只是支持顶点 0 ~ n, 如果顶点是 1 ~ n, 自行更改 只要把顶点的值减 1 就行了
	// 这里假设是 0 ~ n
	cin >> V >> E >> s;
	for(int i = 0; i < E; ++i){
	    int from, to, cost;
	    cin >> from >> to >> cost;
	    edge e;
	    e.to = to;
	    e.cost = cost;
	    G[from].push_back(e);
	}
}

void Dijkstra(int s){
    priority_queue, greater

> que; // 要空一个格 fill(d, d + V, INF); que.push(P(0, s));     d[s] = 0;     while(!que.empty()){ P p = que.top(); que.pop(); int v = p.second; // first 储存最短距离 second 储存的是顶点的坐标 if(d[v] < p.first) continue; // 一直寻找,直到找到符合最短距离的 v 点 for(int i = 0; i < (int)G[v].size(); ++i){ edge e = G[v][i]; // v -> e.to 的边 if(d[e.to] > d[v] + e.cost){ d[e.to] = d[v] + e.cost; que.push(P(d[e.to], e.to)); } }     } } void solve(){ creat(); Dijkstra(s); for(int i = 0; i < V; ++i) cout << d[i] << ' '; // 输出到达各个顶点的最短距离, 如果无法到达结果为 INF } int main(){ solve(); return 0; }

SPFA

#include 
#include 
#include 

using namespace std;

struct edge{
	int to, cost;
};

const int MAX = 10001;
const int INF = 0x3f3f3f3f; // 假设这是无法到达某一点的距离

vector G[MAX]; // 图
int visit[MAX]; // 是否访问了
int d[MAX];
int used[MAX];
int V; // 顶点数
int E; // 边数
int s; // 出发的点

void creat(){
	// 因为只是支持顶点 0 ~ n, 如果顶点是 1 ~ n, 自行更改 只要把顶点的值减 1 就行了
	// 这里假设是 0 ~ n
	cin >> V >> E >> s;
	for(int i = 0; i < E; ++i){
	    int from, to, cost;
	    cin >> from >> to >> cost;
	    edge e;
	    e.to = to;
	    e.cost = cost;
	    G[from].push_back(e);
	}
}

void BFS_Dijkstra(int s){
    queue que;
    fill(d,  d + V, INF);
    que.push(s);
    d[s] = 0;

    while(!que.empty()){
        int v = que.front(); que.pop();
        visit[v] = 0; // 回溯 回到 v 点, 再继续向其他点扩展
        for(int i = 0; i < (int)G[v].size(); ++i){
            edge e = G[v][i];
            if(d[e.to] > d[v] + e.cost){
                d[e.to] = d[v] + e.cost;
                if(!visit[e.to]){
                    visit[e.to] = 1;
                    que.push(e.to);
                }
            }
        }
    }
}

void solve(){
	creat();
	BFS_Dijkstra(s);
	for(int i = 0; i < V; ++i) cout << d[i] << ' '; // 输出到达各个顶点的最短距离, 如果无法到达结果为 INF
}

int main(){
	solve();
	return 0;
}

Bellman_Ford算法

#include 
#include 

using namespace std;

// 边
struct edge{
    int from, to, cost;
};

const int INF = 0x3f3f3f3f;
const int V_MAX = 10001; // 顶点的最大数目
const int E_MAX = 10001; // 边的最大数目
int V; // 顶点数  一样是 0 ~ n
int E; // 边数
int s; // 起点
edge es[E_MAX];
int d[V_MAX];

void creat(){ // 构造图, 另一种构建方法
    cin >> V >> E >> s;
    for(int i = 0; i < E; ++i){
        cin >> es[i].from >> es[i].to >> es[i].cost; // from -> to 的边的距离 = cost
    }
}

void Bellman_Ford(int s){
    fill(d, d + V, INF);
    d[s] = 0;

    while(true){
        bool update = false;
        for(int i = 0; i < E; ++i){
            edge e = es[i];
            if(d[e.from] != INF && d[e.to] > d[e.from] + e.cost){ // 不断寻找到达e.to 的最短距离
                d[e.to] = d[e.from] + e.cost;
                update = true;
            }
        }
        if(!update) break; // 如果没有最短的路径可寻找了, 退出!
    }
}

// 求负圈的算法
// 因为最短路不会经过同一个点两次(也就是说罪过通过 V - 1条边,whlie(true) 最多执行 V - 1次)
// 反之,如果存在从 s 可达的负圈,那么在第 | V |次循环中也会更新 d 的值
 
bool find_negative_loop(){
    memset(d, 0, sizeof(d));

    for(int i = 0; i < V; ++i){
        for(int j = 0; j < E; ++j){
            edge e = es[j];
            if(d[e.to] > d[e.from] + e.cost){
                d[e.to] = d[e.from] + e.cost;
                if(i == V - 1) return false;
            }
        }
    }
    return true;
}

void solve(){
    creat();
    Bellman_Ford(s);
    for(int i = 0; i < V; ++i) cout << d[i] << ' '; // 输出最短距离
}

int main(){
    solve();
    return 0;
}


你可能感兴趣的:(图论)