目录
1.floyd算法时间复杂度分析
对于图论来说,检查数据范围至关重要,那么我们现在看到节点的数目为一千,边的数目为一万。
而floyd算法的时间复杂度是多少呢?
O(v3)也就是说我们的floyd算法几乎只与节点有关,而我们现在的数据范围恰好可行。
那么,现在回归题目,我们想一想运行一个floyd算法能够得到一个什么结果呢?
2.floyd算法的应用及代码
floyd算法运行结果是,图中任意两个点之间的最小长度都被求了出来,也就是说,我们可以很轻松地解决这个问题。(洛谷有开O2优化的选项,所以在代码中没有开启)
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int dist[N][N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n, m;
cin >> n >> m;
memset(dist, 0x3f, sizeof(dist));
for (int i = 1; i <= m; i++) {
int a, b, c;
cin >> a >> b >> c;
dist[a][b] = min(dist[a][b], c);
}
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}
}
}
int ans = 0;
for (int i = 2; i <= n; i++) {
ans += dist[1][i];
ans += dist[i][1];
}
cout << ans << "\n";
return 0;
}
3.迪姐克斯拉算法的分析及反向建边的解释。
现在,我们可以再来想一想迪姐克斯拉算法算法的运行结果是什么?
就是你指认的对应点到任意点的最小值,不是恰好符合题意嘛?
我们还要注意,最后我们还需要返回邮局,也就是说我们还需要反向求出最小值,我们该怎么求呢?
我们现在采用的迪姐克斯拉算法算法没有这样的反向最小值功能(如果非要搞得话比floyd复杂度都要高)
那么我们现在应该怎么办呢?
答案是建立返图,让多到一变成一到多,通俗来讲就是把邻接矩阵倒过来,这样的话发生了什么?
假设要问从x到1的最短路,为x->a->b->c->1,也就是说x->a,a->b,b->c,c->1都有路可走,那么我们想想,从x开始x->a,a->b,b->c,c->1的最短路。把邻接矩阵倒过来,不就是从1开始1->c,c->b,b->a,a->x的最短路吗?于是这时,我们把x->a,a->b,b->c,c->1这4条路径变为1->c,c->b,b->a,a->x,然后从1开始跑最短路,而它们的最短路是一样的。
如果我们用bellman算法怎么实现反向建边呢?
答案就是起点终点互换。
SPFA算法应该也一样,我会在之后的博客中详细解释这些,目前我们只需要看一看缔结克斯啦算法。
#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int g[N][N];
int dist[N];
bool st[N];
int n,m;
void dijkstra()
{
memset(dist,0x3f,sizeof(dist));
memset(st,0,sizeof(st));
dist[1]=0;
for(int i=0;i<n;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
{
if(!st[j]&&(t==-1||dist[t]>dist[j]))
t=j;
}
st[t]=true;
for(int j=1;j<=n;j++)
{
dist[j]=min(dist[t]+g[t][j],dist[j]);
}
}
}
void over()//这个函数主要用于将邻接矩阵进行翻转。
{
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
int t;
t=g[i][j];
g[i][j]=g[j][i];
g[j][i]=t;
}
}
}
/*反向建边翻转哪里用的到呢?其实很简单,就是在一对多求一次,多对一还需要求一次的时候*/
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
memset(g,0x3f,sizeof(g));
for(int i=1;i<=m;i++)
{
int a,b,c;
cin>>a>>b>>c;
g[a][b]=min(g[a][b],c);
}
dijkstra();
int ans=0;
for(int i=1;i<=n;i++)
{
ans+=dist[i];
}
over();//其实也就是反向建边。
dijkstra();
for(int i=1;i<=n;i++)
{
ans+=dist[i];
}
cout<<ans<<"\n";
return 0;
}
最后最后最后,让我们思考思考,如何对dijkstra算法中邻接表存储进行反向建边吧。
在邻接矩阵中,我们主要是通过一个邻接矩阵的反转,那么其实这个也很简单,就是通过一个简单的交换起点终点来达到目的。。
add(a,b)
add(b+n,a+n)
这样在一个数组中就存放下了,我们只需要在往函数里面传递时传递1+n进行初始化就行了。