最短路径

来源:互联网 发布:晋业服装软件 编辑:程序博客网 时间:2024/04/28 07:55

先上一个问题:

---------------------------------------------------------------------------------


给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。

Input:
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点t。
(1<n<=1000, 0<m<100000, s != t)

Output:
输出 一行有两个数, 最短距离及其花费。

Sample Input:
3 2
1 2 5 6
2 3 4 5
1 3


Sample Output:

9 11

---------------------------------------------------------------------------------


然后先上一个主函数:

int main() {int n, m;while (cin >> n >> m) {vector<vector<int>> edge(n + 1, vector<int> (n + 1, INF));vector<vector<int>> value(n + 1, vector<int> (n + 1, INF));while (m--) {int a, b, d, p;cin >> a >> b >> d >> p;edge[a][b] = edge[b][a] = d;value[a][b] = value[b][a] = p;}for (int i = 1; i <= n; i++) {edge[i][i] = 0;value[i][i] = 0;}int start, end;cin >> start >> end;dijkstra(edge, value, start, end);dfs_dist(edge, value, start, end);bfs_dist(edge, value, start, end);floyd(edge, value, start, end);}return 0;}


一、深度优先搜索:


深度优先搜索,就是搜完一个点,接着一个点,用递归的方式进行搜索。复杂度比较大。用上一些剪枝可以节省时间。


void dfs(vector<vector<int>>& edge, vector<vector<int>>& value, vector<bool>& visited, int start, int end, int dist, int cost, int& res_dist, int& res_cost) {if (dist > res_dist) {  //如果dist大于当前最优解了,就结束当前次的搜索return;}if (start == end) { //搜索到了终点if (dist <= res_dist) {res_dist = dist;res_cost = min(res_cost, cost);}return;}for (int i = 1; i < visited.size(); i++) {if (start != i && INT_MAX != edge[start][i] && !visited[i]) { //判断该点是否自身,是否有连接,是否未访问visited[i] = true;dfs(edge, value, visited, i, end, dist + edge[start][i], cost + value[start][i], res_dist, res_cost);visited[i] = false;}}}void dfs_dist(vector<vector<int>>& edge, vector<vector<int>>& value, int start, int end) {int n = edge.size() - 1;vector<bool> visited(n + 1, false); //初始访问为falseint res_dist = INT_MAX;int res_cost = INT_MAX;dfs(edge, value, visited, start, end, 0, 0, res_dist, res_cost);cout << res_dist << ' ' << res_cost << endl;}


二、广度优先搜索:


广度优先搜索通常用一个queue来记录下一次要访问的点。


void bfs_dist(vector<vector<int>>& edge, vector<vector<int>>& value, int start, int end) {int n = edge.size() - 1;vector<int> dist(n + 1, INT_MAX);  //初始距离为INT_MAXvector<int> cost(n + 1, INT_MAX);vector<bool> visited(n + 1, false); //初始访问为falsequeue<int> Q;Q.push(start);dist[start] = 0;cost[start] = 0;while (!Q.empty()) {int idx = Q.front();Q.pop();visited[idx] = true;for (int i = 1; i <= n; i++) {if(i != idx && INT_MAX != edge[idx][i]) { //先判断是否非当前点 和 相连的点if (dist[idx] + edge[idx][i] < dist[i]) {dist[i] = dist[idx] + edge[idx][i];cost[i] = min(cost[i], cost[idx] + value[idx][i]);}if (!visited[i]) { //如果还没访问过的,就压入队Q.push(i);}}}}cout << dist[end] << ' ' << cost[end] << endl;}


三、经典 Dijkstra 算法:


Dijkstra算法解决的是,单源的最短路径问题,也就是求解从点A到点B的最短距离。

基本思想:

用动规的思想,用dist[i]表示,从点A到点i 的最短距离。初始化的时候为INF。

从点A开始,访问这个点,对他周边连接的点进行辐射,计算他们的最短距离,然后选择一个距离最近的点,访问这个点,设置其为新的起点,然后对其周边连接的点进行辐射,继续计算他们的最短距离。那么如果总共有n个点,循环n次即可访问完所有的点。



void dijkstra(vector<vector<int>>& edge, vector<vector<int>>& value, int start, int end) {int n = edge.size() - 1;vector<bool> vistied(n + 1, false); //初始访问为falsevector<int> dist(n + 1, INT_MAX);  //初始距离为INT_MAXvector<int> cost(n + 1, INT_MAX);dist[start] = 0;  //先设置start点的dist为0cost[start] = 0;for (int i = 1; i <= n; i++) {int MIN = INT_MAX;int idx = -1;for (int j = 1; j <= n; j++) {  //找一个未访问过的,距离最近的点if (!visited[j] && dist[j] < MIN) {idx = i;MIN = dist[j];}}visited[idx] = true;  //确定该点后,设为已访问for (int k = 1; k <= n; k++) {  //更新最短距离if (!visited[k] && dist[idx] + edge[idx][k] <= dist[k]) {dist[k] = dist[idx] + edge[idx][k];cost[k] = min(cost[k], cost[idx] + value[idx][k]);}}}cout << dist[end] << ' ' << cost[end] << endl;}

四、Floyd算法:

Floyd适合多源,具有负权的图。就是动规的思想,从点 i 到点 j 的距离可以看作 从 点i 到 点 k 再到点 j 的距离。

  

void floyd(vector<vector<int>>& edge, vector<vector<int>>& value, int start, int end) {int n = edge.size() - 1;vector<vector<int>> dist(n + 1, vector<int> (n + 1, INF));vector<vector<int>> cost(n + 1, vector<int> (n + 1, INF));for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {dist[i][j] = edge[i][j];cost[i][j] = value[i][j];}}for (int k = 1; k <= n; k++) {for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {if (dist[i][j] >= dist[i][k] + dist[k][j]) {dist[i][j] = dist[i][k] + dist[k][j];cost[i][j] = min(cost[i][j],  cost[i][k] + cost[k][j]);}}}}cout << dist[start][end] << ' ' << cost[start][end] << endl;}

原创粉丝点击