一道很有意思的题。
算法要素:floyd+利用过程量
核心思想:算法可以利用的部分不只有结果量,过程量也会起到一些意想不到的作用。
洛谷题面传送门
题目分析:
一、先说Floyd的本质:
用多了f[i][j]的定义,就会忘了其实它是压掉一维的结果。
最初的定义是f[i][j][k],意为从i到j,只经过1~k之间的点,最短路是多少。
因此转移式为:
f[i][j][k]=min(f[i][j][k-1],f[i][k][k-1]+f[k][j][k-1])。
很容易发现:每一次k只会从k-1转移而来,因此可以压缩一维变成f[i][j]。
二、floyd在这道题中的灵活应用:
每次只用k更新f[i][j],并统计形成的最小环。
--所以为什么每次只用k作为中转点更新f[i][j]?
很简单,因为如果所有值都更新完,则f[i][j]可能包括了点k,
不能保证f[i][j]、a[j][k]、a[k][i]在原图中均呈现为链的形式。
emm可能没说明白,那么就直接看代码吧。
还有一个奇怪的bug:
如果初值给的太大,有爆int的情况。
所以要注意初值如果赋成1e9+7,而且会出现1e9+7+1e9+7+一个其他值,那么就有可能爆int。
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e2+30;
long long f[maxn][maxn],a[maxn][maxn],ans=1e9+7;
int n,m;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
if(i!=j) a[i][j]=f[i][j]=1e9+7;
for(int i=1;i<=m;++i)
{
int x,y;
long long w;
scanf("%d%d%lld",&x,&y,&w);
a[x][y]=a[y][x]=f[x][y]=f[y][x]=w;
}
for(int k=1;k<=n;++k)
{
for(int i=1;i<k;++i)
for(int j=i+1;j<k;++j)
ans=min(ans,f[i][j]+a[j][k]+a[k][i]);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]),f[j][i]=f[i][j];
}
if(ans==1e9+7) printf("No solution.\n");
else printf("%lld\n",ans);
return 0;
}