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

图的构造

#include <vector>
#include <iostream>

using namespace std;

struct edge{
	int to, cost;
};

const int MAX = 1000;

vector<edge> 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 <vector>
#include <iostream>

using namespace std;

struct edge{
	int to, cost;
};

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

vector<edge> 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 <vector>
#include <iostream>
#include <queue>
#include <utility>

using namespace std;

struct edge{
	int to, cost;
};

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

vector<edge> 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<P, vector<P>, greater<P> > 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 <vector>
#include <iostream>
#include <queue>

using namespace std;

struct edge{
	int to, cost;
};

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

vector<edge> 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<int> 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 <iostream>
#include <cstring>

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;
}


  • 7
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
分支限界法(Branch and Bound)是一种用于求解组合优化问题的搜索算法,特别是在求解最路径问题上,常用于解决像旅行商问题(Traveling Salesman Problem, TSP)这类NP完全问题。在处理单源路径问题时,虽然Dijkstra算法和Floyd-Warshall算法更常见且效率更高,但分支限界法在处理大规模图或者有额外约束的情况时会很有用。 在C++中实现分支限界法解决单源路径问题,比如带有特定限制的TSP,可能会使用类似于A*搜索(A* Search Algorithm)的启发式搜索策略。以下是一个简化的步骤: 1. **定义问题状态**:通常表示为图中的节点集合和当前路径的成本(如距离或时间)。 2. **状态空间搜索**: - 创建一个优先队列来存储待探索的状态,初始化时只包含起点。 - 当队列不为空时,取出状态进行扩展(生成子节点)。 - 对每个子节点计算其成本,并应用约束条件(如时间窗口、访问顺序等)。 - 如果满足终止条件(找到目标路径或证明无法达到目标),结束搜索;否则,将满足条件的子节点加入优先队列。 3. **剪枝策略**: - 使用上界(Upper Bound)和下界(Lower Bound)进行剪枝,如果某个路径的下界大于已知的最优解,可以直接忽略。 - 可能还会使用启发式函数(Heuristic Function)来评估潜在路径的可能性,减少不必要的搜索。 4. **路径回溯**:当找到最优解时,需要回溯到搜索树中的起始节点,生成完整的路径。 相关问题: 1. 分支限界法如何在最路径问题中避免无效搜索? 2. A*搜索中的启发式函数是什么?如何选择一个合适的启发式函数? 3. 如何在C++中实现优先队列结构来支持分支限界搜索? 请告诉我你是否对分支限界法在最路径中的具体实现细节感兴趣,或者想了解其他相关问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值