思路:问题在于求一个i->j不含k的路径。此时假设k为环中最大的序号点,则d[i][j]不会包含点k,k+1,k+2...。若真正的最小环包含点k,k+1,k+1...,则当前求得的不是全局最小环。
注意:
1、遍历顺序k、i、j(先遍历经过点)
2、求ans一定要放在更新d[i][j]之前,因为在之前最短路更新过程中,k没有参与更新,所以dis[i][j]所表示的路径中不会出现k,如果成立,则一定是一个环。
3、遍历起终点。求最小环i=1~k-1,j=i+1~k-1(因为不能经过点k)。朴素Floyd都是1~n
#include<iostream>
#include<string.h>
#define INF 1<<27
using namespace std;
int n,m;
int g[251][251];
int d[251][251];
int ans=INF;
void Floyd()
{
int i,j,k;
for (k=1;k<=n;k++)
{
for (i=1;i<k;i++)//不能经过k
for (j=i+1;j<k;j++)//不能经过k
ans=min(ans,d[i][j]+g[j][k]+g[k][i]);//保证至少经过3个点
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
int main()
{
int i,a,b,t,j;
cin>>n>>m;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
d[i][j]=INF;g[i][j]=INF;
}
for (i=0;i<m;i++)
{
cin>>a>>b>>t;
g[a][b]=min(t,g[a][b]);
g[b][a]=min(t,g[b][a]);
d[a][b]=g[a][b];
d[b][a]=g[b][a];
}
Floyd();
if (ans==INF)
cout<<"He will never come back."<<endl;
else cout<<ans<<endl;
return 0;
}