首先处理出两点之间最短路,设状态f[i][j]表示j状态下结尾为i的最短路,所以有转移f[i][j]=f[k][j|(1<<(k-1))]+dis[i][k];
初状态就是f[i][(1<<(i-1))]=dis[1][i],因为忽略了第一个点,在枚举的时候后面的点都要为i-2,具体看代码。
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int n,m;
int head[20],cnt=1;
int used[20][20],dis[20][20];
int f[20][(1<<18)+5],dp[(1<<18)+5],tot=0x3f3f3f3f;
struct node
{
int to,nxt,val;
}edge[200005];
struct wee
{
int val,pos;
}xz[20][20];
void init()
{
memset(head,-1,sizeof(head));
memset(dis,0x3f,sizeof(dis));
memset(dp,0x3f,sizeof(dp));
}
void add(int from,int to,int val)
{
edge[cnt].to=to;
edge[cnt].val=val;
edge[cnt].nxt=head[from];
head[from]=cnt++;
}
int cmp(wee x,wee y)
{
return x.val<y.val;
}
queue<int>M;
void spfa(int rt)
{
dis[rt][rt]=0;
used[rt][rt]=1;
M.push(rt);
while(!M.empty())
{
int u=M.front();M.pop();
for(int i=head[u];i!=-1;i=edge[i].nxt)
{
int to=edge[i].to;
if(dis[rt][to]>dis[rt][u]+edge[i].val)
{
dis[rt][to]=dis[rt][u]+edge[i].val;
if(used[rt][to])continue;
M.push(to);used[rt][to]=1;
}
}
used[rt][u]=0;
}
}
int main()
{
scanf("%d%d",&n,&m);init();
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);add(b,a,c);
}
for(int i=1;i<=n;i++)spfa(i);
memset(f,0x3f,sizeof(f));
for(int i=2;i<=n;i++)
{
f[i][(1<<(i-2))]=dis[1][i];
}
for(int j=0;j<=(1<<(n-1))-1;j++)
{
for(int i=2;i<=n;i++)
{
if(j&(1<<(i-2)))
{
for(int k=2;k<=n;k++)
{
if(!(j&(1<<(k-2))))
{
f[k][j|(1<<(k-2))]=min(f[k][j|(1<<(k-2))],f[i][j]+dis[i][k]);
}
}
}
}
}
for(int i=0;i<=(1<<(n-1))-1;i++)
{
for(int j=2;j<=n;j++)
{
dp[i]=min(dp[i],f[j][i]);
}
}
for(int i=0;i<=(1<<(n-1))-1;i++)
{
tot=min(tot,max(dp[i],dp[(1<<(n-1))-1-i]));
}
printf("%d",tot);
return 0;
}