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 ...
随机推荐
- arduino uno r3的数据类型
char 一个字节,存储一个字符值.字符文字用单引号写成:'A' unsigned char 无符号,一个字节 byte 一个字节,无符号数, int 2字节,这产生-32768至32767的范围. ...
- 第一章 C#入门(Windows窗体应用程序)(二)
C#窗体应用程序(二) [案例]设计登录界面,效果如下: [案例实现步骤] 1.新建项目(Windows控制台应用程序 文件→新建→项目:选择“项目类型”为Visual C#,“模板”为Windows ...
- ssh 制作免密登录(免密登录多台服务器)
场景:服务器B (192.168.1.101)免密登录A(192.168.1.100)服务器 1.登录服务器B ①生产公钥 ssh-keygen -t rsa Enter file in which ...
- 关于bit,bin文件的一些研究
关于bit,bin文件的一些研究 bit文件里面有head information 但bin文件里面并不包含 bit 文件里面包含如下信息 SPI flash 时钟需要用到的源语 watchdog 设 ...
- 一次Windows 安装问题
在 thinpad x250上安装 windows 10时,提示"安装程序无法创建新的系统分区,也无法定位现有系统分区". x250 的主板上自带一个16G的闪存且标识为 主分区, ...
- localStorage小结
使用HTML5可以在本地存储用户的浏览数据.. 什么是 HTML5 Web 存储? 在HTML5中,新加入了一个localStorage特性,这个特性主要是用来作为本地存储来使用的,解决了cookie ...
- 廖雪峰Java7处理日期和时间-2Data和Calendar-1Date
计算机中如何存储和表示日期和时间 Epoch Time:从1970年1月1日零点(格林威治时区/GMT+00:00)到现在经历的秒数,也叫timestamp, 例如: 秒级: * 北京 2016-11 ...
- 谈谈线上CPU100%排查套路
知识点总结 ---------------------------------------------------------------------------------------------- ...
- Java 中 Gson的使用
JSON 是一种文本形式的数据交换格式,它比XML更轻量.比二进制容易阅读和编写,调式也更加方便;解析和生成的方式很多,Java中最常用的类库有:JSON-Java.Gson.Jackson.Fast ...
- IDLE的GUI交互模式下完美清屏
IDLE的GUI交互模式下完美清屏==============================================================================1.首先把 ...