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 ...
随机推荐
- SSL&TLS渗透测试
什么是TLS&SSL? 安全套接字层(SSL)和传输层安全(TLS)加密通过提供通信安全(传输加密)和为应用程序如网络.邮件.即时消息和某些虚拟私有网络(VPN)提供隐私的方式来确保互联网和网 ...
- java android 捕获未处理异常
1. 定义一个异常处理类 public class ExceptionHandler implements Thread.UncaughtExceptionHandler { public Excep ...
- Web前端新手想提升自身岗位竞争力,需做好这3件事!
Web前端开发行业的发展前景毋庸置疑,只要是互联网企业,几乎都需要Web前端开发工程师.虽然Web前端入行门槛低,但竞争逐渐激烈,想要取得高薪,就一定要具备强大的实力.那么,在重庆Web前端培训学习中 ...
- 使用openresty && minio && thumbor 构建稳定高效的图片服务器
备注: minio 是一个开源的s3 协议兼容的分布式存储,openresty nginx+lua 高性能可扩展的nginx 衍生版,thumbor 基于python 的图片处理服务器,支持图片的裁剪 ...
- Java面试题 OOAD & UML+XML+SQL+JDBC & Hibernate
二.OOA/D 与UML 部分:(共6 题:基础2 道,中等难度4 道) 96.UML 是什么?常用的几种图?[基础] 答:UML 是标准建模语言:常用图包括:用例图,静态图(包括类图.对象图和包图) ...
- linux中telnet后退出连接窗口的方法?
linux中telnet后退出连接窗口 [root@a cron]# telnet www.baidu.com 80Trying 115.239.211.112...Connected to www. ...
- linux git 保存用户名和密码
一.通过文件方式 1.在~/下, touch创建文件 .git-credentials, 用vim编辑此文件,输入内容格式: touch .git-credentials vim .git-crede ...
- denyhosts、中文文档乱码、端口占用查询
1.安装 denyhosts, 设置 hosts.allow ,系统自动将攻击的ip 添加如 hosts.deny2.打开中文文档乱码, 将文档下载到windows, 通过富文本编辑器查看文档编码3. ...
- 实验四:xl命令的常见子命令以及操作
实验名称: xl命令的常见子命令以及操作 实验环境: 这里我们需要正常安装一台虚拟机,如下图: 我们这里以一台busybox为例,来进行这些简单的常见的操作: 实验要求: 这里我们准备了5个常见操作: ...
- Vue 折叠面板Collapse在标题上添加组件后,阻止面板冒泡的用法
iView组件中,折叠面板Collapse点击面板标题部分,会出现面板收起或展开的效果.那么在面板标题后面再添加下拉框之类的组件时,会出现跟面板点击一样的效果,这时候就需要阻止冒泡的用法了.具体代码: ...