标签:问题 reg 无限 inline pre span class spfa math
这题竟然没有题解,那我就来发一篇吧。
第一眼看到这题:最小环?什么鬼!用 SPFA 好像很麻烦欸。然后一看数据:\(1\leq n\leq 100\)。好吧这题用邻接矩阵和 floyd 就能过。
floyd 是一种动态规划求最短路径的方法,代码极短,并且很好理解(代价就是在最短路径算法中无人能敌的 \(\Theta(n^3)\) 的时间复杂度)。那么最短环怎么办呢,只要稍微改一下就行了!
这是一个正常的 floyd 的核心代码(无向图):
for(rg int k=1;k<=n;++k) //经不经过 k。
{
for(rg int i=1;i<=n;++i) //从 i 点。
{
for(rg int j=1;j<=n;++j) //到 j 点。
{
if(f[i][j]>f[i][k]+f[k][j]) //如果经过 k 更短的话更新。
f[i][j]=f[i][k]+f[k][j];
f[j][i]=f[i][j]; //无向图要存双向。
}
}
}
但是我们要让它为环,怎么办呢?那就在找完最短路之后再加一个循环找回路!(简单粗暴)
我们可以用一个邻接矩阵存下这张图,如果两点不联通就为无限大(我们这里就用一个很大的数字代替无限大),所以 \(f_{i,j}+a_{i,k}+a_{k,j}\) 即为一个环的权值。穷举 \(i,j,k\) 不断更新答案就行了。
for(rg int k=1;k<=n;++k)
{
for(rg int i=1;i<k;++i)
{
for(rg int j=i+1;j<k;++j)
{ //这里的 a 是邻接矩阵存图。f 数组就是最短路。
if(ans>f[i][j]+a[i][k]+a[k][j]) //因为 a 的初始值为 1e8,就省去判断。
ans=f[i][j]+a[i][k]+a[k][j]; //更新答案。
}
}
for(rg int i=1;i<=n;++i)
{
for(rg int j=1;j<=n;++j)
{
if(f[i][j]>f[i][k]+f[k][j]) //如果更短的话更新。
f[i][j]=f[i][k]+f[k][j];
f[j][i]=f[i][j];
}
}
}
最后提醒:要注意这是无向图,对于每次输入要存正反两次。
完整无注释代码:
#include<bits/stdc++.h>
using namespace std;
#define maxn 110
#define inf 1e8
#define rg register
int n,m,u,v,w,ans=inf;
int a[maxn][maxn],f[maxn][maxn];
int main()
{
cin>>n>>m;
for(rg int i=1;i<=n;++i)
{
for(rg int j=1;j<=n;++j)
{
if(i!=j)
{
a[i][j]=inf;
f[i][j]=inf;
}
}
}
for(rg int i=1;i<=m;++i)
{
cin>>u>>v>>w;
a[u][v]=w;
a[v][u]=w;
f[u][v]=w;
f[v][u]=w;
}
for(rg int k=1;k<=n;++k)
{
for(rg int i=1;i<k;++i)
{
for(rg int j=i+1;j<k;++j)
{
if(ans>f[i][j]+a[i][k]+a[k][j])
ans=f[i][j]+a[i][k]+a[k][j];
}
}
for(rg int i=1;i<=n;++i)
{
for(rg int j=1;j<=n;++j)
{
if(f[i][j]>f[i][k]+f[k][j])
f[i][j]=f[i][k]+f[k][j];
f[j][i]=f[i][j];
}
}
}
if(ans==inf)
cout<<"No solution."<<endl;
else
cout<<ans<<endl;
return 0;
}
其实代码很短的,只是个人码风会显得长。
标签:问题 reg 无限 inline pre span class spfa math
原文地址:https://www.cnblogs.com/win10crz/p/12859754.html