昨天刚学习完最短路的算法,今天开始练题发现我是真的菜呀,居然能忘记邻接表是怎么写的,真的是菜的真实......

为了弥补自己的菜,我决定这道题我就要用五种办法写出,并在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)集合中的节点为中间节点的最短路径的长度。

  1. 若最短路径经过点k,D(i, j, k) = D(i, k, k - 1) + D(k, j, k - 1);
  2. 若最短路径不经过点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)的更多相关文章

  1. poj 2387 Til the Cows Come Home (最短路,dijkstra模版题)

    题目 #define _CRT_SECURE_NO_WARNINGS #include<string.h> #include<stdio.h> #include<math ...

  2. 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 ...

  3. POJ.2387 Til the Cows Come Home (SPFA)

    POJ.2387 Til the Cows Come Home (SPFA) 题意分析 首先给出T和N,T代表边的数量,N代表图中点的数量 图中边是双向边,并不清楚是否有重边,我按有重边写的. 直接跑 ...

  4. POJ 2387 Til the Cows Come Home

    题目链接:http://poj.org/problem?id=2387 Til the Cows Come Home Time Limit: 1000MS   Memory Limit: 65536K ...

  5. POJ 2387 Til the Cows Come Home(最短路 Dijkstra/spfa)

    传送门 Til the Cows Come Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 46727   Acce ...

  6. 怒学三算法 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 ...

  7. 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 ...

  8. 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 ...

  9. 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 ...

随机推荐

  1. mongodb集群配置主从模式

    测试环境 操作系统:CentOS 7.2 最小化安装 主服务器IP地址:192.168.197.21 master-node 从服务器IP地址:192.168.197.22 slave-node 关闭 ...

  2. DokuWiki 插件使用

    本身DokuWiki提供了一些公共,但是不是很强大,所以可以安装一些插件. 安装方法可以参考:https://www.dokuwiki.org/extensions 下面列举出我觉得好用的一些插件: ...

  3. python读取指定字节长度的文本

    软件版本 Python 2.7.13;   Win 10 场景描述 1.使用python读取指定长度的文本: 2.使用python读取某一范围内的文本. Python代码 test.txt文本内包含的 ...

  4. ubuntu14.04 安装jdk1.8及以上

    安装xmind1.8 碰到jvm版本太低的错误: Version 1.7.0_131 of the JVM is not suitable for this product. Version: 1.8 ...

  5. Java笔试面试题整理第八波

    转载至:http://blog.csdn.net/shakespeare001/article/details/51388516 作者:山代王(开心阳) 本系列整理Java相关的笔试面试知识点,其他几 ...

  6. Linux下载命令之rpm和yum比较

    RPM和YUM比较 rpm 是linux的一种软件包名称,以.rmp结尾,安装的时候语法为:rpm -ivh,rpm包的安装有一个很大的缺点就是文件的关联性太大,有时候装一个软件要安装很多其他的软件包 ...

  7. JVM 符号引用与直接引用

       Java类从加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括,加载 ,验证 , 准备 , 解析 , 初始化 ,卸载 ,总共七个阶段.其中验证 ,准备 , 解析 统称为连接.     ...

  8. leetcode每日刷题计划-简单篇day3

    收到swe提前批面试hhh算是ep挂了的后续 努力刷题呀争取今年冲进去! Num 21 合并两个有序链表 Merge Two Sorted Lists 注意新开的链表用来输出结果的是ListNode ...

  9. 【学习】基础知识:数组和矢量计量【Numpy】

    Numpy是高性能科学计算和数据分析的基础包.功能如下: ndarray 一个具有矢量算法运算和复杂广播能力的快速且节省空间的多维数组 用于对整组数据进行快速运算的标准数学函数(无需编写循环) 用于读 ...

  10. python大法好——Python2.x与3​​.x版本区别

    python大法好——Python2.x与3​​.x版本区别 Python的3​​.0版本,常被称为Python 3000,或简称Py3k.相对于Python的早期版本,这是一个较大的升级. 为了不带 ...