算法引入:
*求一个图G中的最小环路的朴素算法为:每次找到一条边,删除了求这两点之间的最短路径;
*若能求出,则这条最短路径与原来的边构成一个环,不过时间复杂度略高;
*算法思想;
*Floyd算法是按照顶点的编号增加的顺序更新最短路径的;
*如果存在最小环,则会在这个环中的点编号最大的那个点u更新最短路径之前发现这个环;
*即当点u被拿来更新i到j的最短路径的时候,可以发现这个闭合环路;
*发现的方法是,更新最短路径前,遍历i,j点对,一定会发现某对i到j的最短路径长度:
*dist[i][j]+map[j][u]+map[u][i]!=INF,这时s的i和j是当前环中挨着点u的两个点;
*因为在之前的最短路径更新过程中,u没有参与更新,所以dist[i][j]所表示的路径中不会有点u,即一定为一个环;
*
*如果在每个新的点拿来更新最短路径之前遍历i和j验证上面的式子,虽然不能遍历到所有的环;
*但是由于dist[i][j]是i到j点的最短路径m所以肯定可以遍历到最小的环;
*
*如果有负权环,则该算法失效,因为包含负环的图上,dist[i][j]已经不能保证i到j的路径上不会经过同一个点多次了;
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int g[155][155], dis[155][155];
LL ans;
void floyd(int n)
{
for(int k = 1; k <= n; ++k)
{
for(int i = 1; i <= k - 1; ++i)
for(int j = i + 1; j <= k - 1; ++j)
if(ans > g[i][j] + dis[i][k] + dis[k][j]) ans = (LL)g[i][j] + dis[i][k] + dis[k][j];
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n ; ++j)
if(g[i][j] > g[i][k] + g[k][j]) g[i][j] = g[i][k] + g[k][j];
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n, m;
while(cin >> n >> m)
{
memset(g, 0x3f3f3f3f, sizeof(g));
memset(dis, 0x3f3f3f3f, sizeof(dis));
for(int i = 0; i < m; ++i)
{
int u, v, w;
cin >> u >> v >> w;
g[u][v] = g[v][u] = dis[u][v] = dis[v][u] =w;
}
ans = 0x3f3f3f3f;
floyd(n);
if(ans == 0x3f3f3f3f) cout << "No solution." << endl;
else cout << ans << endl;
}
return 0;
}
- 版权声明:本文基于《知识共享署名-相同方式共享 3.0 中国大陆许可协议》发布,转载请遵循本协议
- 文章链接:http://www.carlstedt.cn/archives/1411 (转载时请注明本文出处及文章链接)


发表评论
快来吐槽一下吧!