题意:给你一个n个点加权无向图,要你从里面找一个路径最短的环,每个点只能经过一次 ,如果存在这样的最短环则把路径给打印出来,如果有多个,打印一个出来即可。
本题的重点是,如果用简单的用floyd求最小环,你会发现在求最短路的过程中有很多点是重复经过的。现在的问题是怎么找没有重复经过同一个点的最小环,每次修改最小环是都记录下当前的path
我们可以做一个限制 就是k比i,j都大,假如说求u->i->j->k->v的,最小环,如果u k v都确定的情况下,只需要找通过i j的最小路程,现在要保证,k与之前的i,j不相同,所以需要设置k比i,j都大,这道题的难点解决了
还有一点就是本题输出用了一点二分的思想,递归每次找i到k和k到j两个区间
AC代码
#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
const int N=105;
#define inf 0x3f3f3f
typedef long long ll;
int h[N][N],d[N][N];
int pos[N][N];
int path[N],cnt;
void getpath(int i,int j)
{
if(!pos[i][j])
return ;
int k=pos[i][j];
getpath(i,k);
path[cnt++]=k;
getpath(k,j);
}
int main()
{
memset(h,inf,sizeof(h));
int m,n;
scanf("%d%d",&n,&m);
while(m--)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
h[u][v]=h[v][u]=min(h[u][v],w);
}
memcpy(d,h,sizeof(h));
int res=inf;
for(int k=1;k<=n;k++)
{
for(int i=1;i<k;i++)
{
for(int j=i+1;j<k;j++)
{
if((ll)d[i][j]+h[i][k]+h[k][j]<res)
{
res=d[i][j]+h[i][k]+h[k][j];
cnt=0;
path[cnt++]=k;
path[cnt++]=i;
getpath(i,j);
path[cnt++]=j;
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(d[i][j]>d[i][k]+d[k][j])
{
d[i][j]=d[i][k]+d[k][j];
pos[i][j]=k;
}
}
}
}
if(res>=inf)
printf("No solution.\n");
else
{
for(int i=0;i<cnt;i++)
printf("%d ",path[i]);
}
}