POJ-2387.Til the Cows Come Home.(五种方法:Dijkstra + Dijkstra堆优化 + Bellman-Ford + SPFA + Floyd-Warshall)
昨天刚学习完最短路的算法,今天开始练题发现我是真的菜呀,居然能忘记邻接表是怎么写的,真的是菜的真实......
为了弥补自己的菜,我决定这道题我就要用五种办法写出,并在Dijkstra算法堆优化中另外给出邻接表存储实现的操作,唉,真是令人窒息......
言归正传吧,毕竟我这么菜,也不会讲什么大道理......
呜哇呜哇.jpg
原题链接
本题大意:给定n结点,a和b表示其中的两个结点,输出t组a和b和w表示a和b距离w可以互相抵达,求从n走到1的最短路径...
本题思路:建图之后直接单源最短路任意结点之间的最短路随便解,只是有些算法会超时,我这里仅是作为练习算法去练习其他算法,读者可自行尝试......
先给出解决无负权单源最短路的最优算法Dijkstra算法吧,包括其优化:
Dijkstra :我再叙述一下这个算法的作用机理吧,将整个图的结点分为两个部分,一部分为已经确定最短路径的集合S,另一部分当然是n - S, 初始状态下S内不包含任何结点。接着在n - S中挑选一个权值最小的结点,将该结点直接
放进S中表示改结点到源结点的最短路径求解完毕,在n - S中对所有与该结点有公共边的结点做松弛操作,松弛的大体意思就是通过已知的最短路来求解与他相连的边的结点的最短路......
为啥上面我们要在n - S中寻找结点做松弛操作呢,因为S中的结点已经被求出了最短路,那为什么每次找的那个最小值就保证它已经是最短路了呢?这......证明简直花了算法导论一大堆篇章,我看懂了但我不说emm...(其实还是不懂...
小声bb.jpg)
参考代码:
好了,我们要开始写代码了
首先给出没有用堆优化的Dijkstra算法:
//Dijkstra未优化版 : 47ms
#include <iostream>
#include <cstring>
using namespace std; const int maxn = 1e3 + , INF = 0x3f3f3f3f;
int t, n, k, dist[maxn], G[maxn][maxn];
bool vis[maxn]; int Dijkstra(int source) {
for(int i = ; i <= n; i ++)
dist[i] = (i == source ? : INF);
for(int i = ; i <= n; i ++) {
int Min = INF;
for(int j = ; j <= n; j ++)
if(!vis[j] && dist[j] < Min) {
Min = dist[j];
k = j;
}
vis[k] = true;
for(int j = ; j <= n; j ++) {
if(G[k][j] != INF && !vis[j] && dist[j] > dist[k] + G[k][j])
dist[j] = dist[k] + G[k][j];
}
}
return dist[n];
} int main () {
cin >> t >> n;
int a, b, w;
memset(vis, false, sizeof vis);
for(int i = ; i <= n; i ++)
for(int j = ; j <= n; j ++)
G[i][j] = INF;
for(int i = ; i < t; i ++) {
cin >> a >> b >> w;
G[a][b] = min(G[a][b], w);
G[b][a] = min(G[b][a], w);
}
cout << Dijkstra() << endl;
return ;
}
唉,烦人的Vj,每次给的Test time都不一样......
邻接矩阵存储的堆优化的Dijkstra算法:
//堆优化的Dijkstra算法: 141ms
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
using namespace std; typedef pair<int, int> Pii;
const int maxn = + , INF = 0x3f3f3f3f;
int t, n, dist[maxn];
bool vis[maxn];
struct edge {
int to, cost;
};
vector <edge> G[maxn]; void addedge(int u, int v, int w) {
G[u].push_back({v, w});
} int Dijkstra(int source) {
for(int i = ; i <= n; i ++)
dist[i] = (i == source ? : INF);
priority_queue <Pii, vector<Pii>, greater<Pii> > Q;
Q.push(make_pair(, ));
while(!Q.empty()) {
Pii p = Q.top();
Q.pop();
if(vis[p.second]) continue;
vis[p.second] = true;
for(int i = ; i < G[p.second].size(); i ++) {
edge e = G[p.second][i];
if(dist[e.to] > dist[p.second] + e.cost) {
dist[e.to] = dist[p.second] + e.cost;
Q.push(make_pair(dist[e.to], e.to));
}
}
}
return dist[n];
} int main () {
cin >> t >> n;
int a, b, w;
for(int i = ; i < t; i ++) {
cin >> a >> b >> w;
addedge(a, b, w);
addedge(b, a, w);
}
cout << Dijkstra() << endl;
return ;
}
Bellman-Ford:下面叙述一下Bellman-Ford算法的作用机理。
(1)初始化:将除源点外的所有顶点的最短距离估计值 d[v] ←+∞, d[s] ←0;
(2)迭代求解:反复对边集E中的每条边进行松弛操作,使得顶点集V中的每个顶点v的最短距离估计值逐步逼近其最短距离;(运行|v|-1次)
(3)检验负权回路:判断边集E中的每一条边的两个端点是否收敛。如果存在未收敛的顶点,则算法返回false,表明问题无解;否则算法返回true,并且从源点可达的顶点v的最短距离保存在 d[v]中。
下面我们给出该算法的代码:
// /*Bellman-Ford算法:172ms
#include <iostream>
#include <cstring>
#include <vector>
using namespace std; typedef pair<int, int> Pii;
struct edge {
int to, cost;
};
const int maxn = + , INF = 0x3f3f3f3f;
vector <edge> G[maxn];
int t, n, dist[maxn]; void addedge(int u, int v, int w) {
G[u].push_back({v, w});
} int Bellman_Ford(int source) {
bool flag;
for(int i = ; i <= n; i ++)
dist[i] = (i == source ? : INF);
for(int k = ; k < n; k ++) {
flag = false;
for(int i = ; i <= n; i ++) {
for(int j = ; j < G[i].size(); j ++) {
edge e = G[i][j];
if(dist[e.to] > dist[i] + e.cost) {
dist[e.to] = dist[i] + e.cost;
flag = true;
}
}
}
if(!flag) break;
}
return dist[n];
} int main() {
cin >> t >> n;
int a, b, w;
for(int i = ; i < t; i ++) {
cin >> a >> b >> w;
addedge(a, b, w);
addedge(b, a, w);
}
cout << Bellman_Ford() << endl;
return ;
}
// */
SPFA:这是Bellman-Ford算法的一种队列优化算法,具体是怎么个优化法呢,听我下面详细道来......
SPFA算法全称为Shortest Path Fast Algorithm,在1994年由西南交通大学段凡丁提出,与Bellman-Ford算法一样,用于求解含负权的最短路问题以及判断是否存在负权环。在不含负权环的题情况下优先选择堆优化的Dijkstra算法求最短路径,这就避免SPFA出现最坏的情况。SPFA算法的基本思路与Bellman-Ford算法相同,即每个节点都被用作用于松弛其相邻节点的备选节点。相较于Bellman-Ford算法,SPFA算法的提升在于它并不盲目尝试所有节点,而是维护一个备选节点队列,并且仅有节点被松弛后才会放入队列中。整个流程不断重复直至没有节点可以被松弛。
下面给出这个算法的代码吧:
#include <iostream>
#include <queue>
#include <cstring>
using namespace std; struct edge {
int to, cost;
};
const int maxn = + , INF = 0x3f3f3f3f;
vector <edge> G[maxn];
int t, n, now, dist[maxn];
bool vis[maxn]; void addedge(int u, int v, int w) {
G[u].push_back({v, w});
} int Spfa(int source) {
memset(vis, false, sizeof vis);
for(int i = ; i <= n; i ++)
dist[i] = (i == source ? : INF);
queue <int> Q;
Q.push(source);
vis[source] = true;
while(!Q.empty()) {
now = Q.front();
Q.pop();
for(int i = ; i < G[now].size(); i ++) {
edge e = G[now][i];
if(dist[e.to] > dist[now] + e.cost) {
dist[e.to] = dist[now] + e.cost;
if(!vis[e.to]) Q.push(e.to);
}
}
}
return dist[n];
} int main() {
cin >> t >> n;
int a, b, w;
for(int i = ; i < t; i ++) {
cin >> a >> b >> w;
addedge(a, b, w);
addedge(b, a, w);
}
cout << Spfa() << endl;
return ;
}
Floyd-Warshall:这个算法的本事很大,可以用来求所有结点的最短路,但用此算法求单源最短路也是可以的,就显得比较大材小用,本领强其复杂度必然臃肿......好了下面我介绍一下该算法的基本思路吧。
Floyd-Warshall算法通过逐步改进两个顶点之间的最短路径来实现,直到估计是最优的。
是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权(但不可存在负权回路)的最短路径问题,同时也被用于计算有向图的传递闭包[2]。
Floyd-Warshall算法的时间复杂度为O(N3),空间复杂度为O(N2)。
原理:Floyd-Warshall算法的原理是动态规划。
设D(i, j, k)为从i到j的只以(1....k)集合中的节点为中间节点的最短路径的长度。
- 若最短路径经过点k,D(i, j, k) = D(i, k, k - 1) + D(k, j, k - 1);
- 若最短路径不经过点k,则D(i, j, k) = D(i, j, k - 1)。
因此,D(i, j, k) = min(, D(i, j, k - 1), D(i, k, k - 1) + D(k, j, k - 1));。
在实际算法中,为了节约空间,可以直接在原来空间上进行迭代,这样空间可降至二维。
参考代码:
// /*Floyd-Warshall算法:TLE,具体时间不详
#include <iostream>
#include <queue>
#include <cstring>
using namespace std; struct edge {
int to, cost;
};
const int maxn = + , INF = 0x3f3f3f3f;
int t, n, now, dist[maxn][maxn]; int Floyd_Warshall(int source, int End) {
for(int k = ; k <= n; k ++) {
for(int i = ; i <= n; i ++) {
for(int j = ; j <= n; j ++) {
if(dist[i][j] > dist[i][k] + dist[k][j])
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
return dist[source][End];
} int main() {
cin >> t >> n;
int a, b, w;
for(int i = ; i <= n; i ++) {
for(int j = ; j <= n; j ++) {
if(i == j) dist[i][j] == ;
else dist[i][j] = INF;
}
}
for(int i = ; i < t; i ++) {
cin >> a >> b >> w;
dist[a][b] = min(dist[a][b], w);
dist[b][a] = min(dist[b][a], w);
}
cout << Floyd_Warshall(, n) << endl;
return ;
}
// */
这个题目就到此结束吧......
POJ-2387.Til the Cows Come Home.(五种方法:Dijkstra + Dijkstra堆优化 + Bellman-Ford + SPFA + Floyd-Warshall)的更多相关文章
- poj 2387 Til the Cows Come Home (最短路,dijkstra模版题)
题目 #define _CRT_SECURE_NO_WARNINGS #include<string.h> #include<stdio.h> #include<math ...
- POJ 2387 Til the Cows Come Home (图论,最短路径)
POJ 2387 Til the Cows Come Home (图论,最短路径) Description Bessie is out in the field and wants to get ba ...
- POJ.2387 Til the Cows Come Home (SPFA)
POJ.2387 Til the Cows Come Home (SPFA) 题意分析 首先给出T和N,T代表边的数量,N代表图中点的数量 图中边是双向边,并不清楚是否有重边,我按有重边写的. 直接跑 ...
- POJ 2387 Til the Cows Come Home
题目链接:http://poj.org/problem?id=2387 Til the Cows Come Home Time Limit: 1000MS Memory Limit: 65536K ...
- POJ 2387 Til the Cows Come Home(最短路 Dijkstra/spfa)
传送门 Til the Cows Come Home Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 46727 Acce ...
- 怒学三算法 POJ 2387 Til the Cows Come Home (Bellman_Ford || Dijkstra || SPFA)
Til the Cows Come Home Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 33015 Accepted ...
- POJ 2387 Til the Cows Come Home (最短路 dijkstra)
Til the Cows Come Home 题目链接: http://acm.hust.edu.cn/vjudge/contest/66569#problem/A Description Bessi ...
- POJ 2387 Til the Cows Come Home 【最短路SPFA】
Til the Cows Come Home Description Bessie is out in the field and wants to get back to the barn to g ...
- POJ 2387 Til the Cows Come Home Dijkstra求最短路径
Til the Cows Come Home Bessie is out in the field and wants to get back to the barn to get as much s ...
随机推荐
- JavaScript数据类型(第一天)
ECMAScript为JavaScript的标准,javascript为网景公司定义,但并不标准,所以欧洲的组织定义了ESMAScript,定义了网页脚本的标准. js组成 ECMAScript js ...
- 使用mysqlproxy实现mysql读写分离
先说一下什么是读写分离吧. 以三台虚拟机为例,搭建一主一从一代理,全部配置好之后,当从proxy插入数据时,该数据会同时插入主数据库,因为主从关系,从数据库也会有数据.当把从数据库执行slave st ...
- lvs UDP端口负载均衡配置
! Configuration File for keepalived global_defs { notification_email { test@163.com } notification_e ...
- Linux 开机启动 php socket
问题 php socket 服务在服务器重启后无法自动启动,需要添加开机启动脚本.有以下问题 开机延迟3分钟后,再启动socket服务 socket服务有3个模块需要按照先后顺序启动 registe ...
- AIUI开放平台:多轮对话返回前几轮语槽数据
编写云函数: AIUI.create("v2", function(aiui, err){ // 获取 response response = aiui.getResponse() ...
- DDR3初识
DDR3初识 选择2:1 ratio 意味用户总线宽度为DDR物理数据接口宽度的4倍.
- MySQL 5.7临时表空间
MySQL 5.7起,开始采用独立的临时表空间(和独立的undo表空间不是一回事哟),命名ibtmp1文件,初始化12M,且默认无上限. 选项 innodb_temp_data_file_path 可 ...
- LeetCode——727.Minimum Window Subsequence
一.题目链接:https://leetcode.com/problems/minimum-window-substring/ 二.题目大意: 给定两个字符串S和T,要求从S中找出包含T中所有字母的最短 ...
- python之路——14
王二学习python的笔记以及记录,如有雷同,那也没事,欢迎交流,wx:wyb199594 复习 1.迭代器 1.双下方法:不常直接调用,是通过其他语法触发的 2.可迭代的:可迭代协议——含有__it ...
- 从神经网络到卷积神经网络(CNN)
我们知道神经网络的结构是这样的: 那卷积神经网络跟它是什么关系呢?其实卷积神经网络依旧是层级网络,只是层的功能和形式做了变化,可以说是传统神经网络的一个改进.比如下图中就多了许多传统神经网络没有的层次 ...