先Floyd预处理出两点间最短路径,然后状压dp,dp[s][i]表示状态为s的点都遍历了,停在i的最小时间。枚举一个j去转移就好了。然后处理出f[s],表示遍历了s状态的点的最小花费。然后枚举A遍历了哪些点,B必须遍历了其余点与1.取最大值就是最慢的,更新答案即可。复杂度O(2^n *n*n)注意初值只能给dp[1][1]=0.一开始在其他点都是非法的。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 20
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,m,dp[300000][N],mp[N][N],bin[N],f[300000],ans=inf;//dp[s][i],状态为s的点都便利了,现在在i的最小时间
int main(){
// freopen("transport.in","r",stdin);
n=read();m=read();memset(mp,inf,sizeof(mp));
while(m--){
int x=read(),y=read();mp[x][y]=mp[y][x]=read();
}
for(int i=1;i<=n;++i) mp[i][i]=0;
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
memset(dp,inf,sizeof(dp));bin[0]=1;memset(f,inf,sizeof(f));
for(int i=1;i<=n;++i) bin[i]=bin[i-1]<<1;dp[1][1]=0;
for(int s=1;s<bin[n]-1;++s)
for(int i=1;i<=n;++i){
if(dp[s][i]==inf) continue;
for(int j=1;j<=n;++j){
if(s&bin[j-1]||mp[i][j]==inf) continue;
dp[s|bin[j-1]][j]=min(dp[s|bin[j-1]][j],dp[s][i]+mp[i][j]);
}
}
for(int s=0;s<=bin[n]-1;++s)
for(int j=1;j<=n;++j) f[s]=min(f[s],dp[s][j]);
for(int s=0;s<=bin[n]-1;++s){
if(!(s&1)) continue;
int res=max(f[s],f[(bin[n]-1-s)|1]);
ans=min(ans,res);
}printf("%d\n",ans);
return 0;
}