sightseeing trip
求无向图的最小环
显然考虑枚举环上的点 多源最短路
为了避免三点共线的情况 因此要绕开中间的点,这正好符合floyd算法的思想
不经过k 不包括端点 最外层循环每扩大1 相当于允许多经过一个点
为什么只能枚举相邻的点呢?
因为我们必须保证最大的点在中间位置 假如说三点共线的话 最大点在边上 这个距离就已经被更新过了 会出错
而同一个最小环上只有一个最大点 只枚举两侧相邻的点就足够了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#define ll long long
#define pb push_back
using namespace std;
const int N=110;
const int INF=0x3f3f3f3f;
int read()
{
int x=0,f=0,c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return f?-x:x;
}
int n,m;
int d[N][N],e[N][N],p[N][N];
vector <int> path;
void print(int x,int y)
{
if(!p[x][y]) return;
int t=p[x][y];
print(x,t); path.pb(t); print(t,y);
}
int main()
{
n=read(); m=read();
memset(d,0x3f,sizeof d); memset(e,0x3f,sizeof e);
for(int i=1;i<=n;i++) e[i][i]=d[i][i]=0;
for(int i=1;i<=m;i++)
{
int x=read(),y=read();
e[x][y]=e[y][x]=d[x][y]=d[y][x]=min(d[x][y],read());
}
int ret=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]+e[i][k]+e[k][j]<ret)//ll
{
path.clear();
ret=d[i][j]+e[i][k]+e[k][j];
path.pb(i); print(i,j); path.pb(j);path.pb(k);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(d[i][k]+d[k][j]<d[i][j])
{
d[i][j]=d[i][k]+d[k][j];
p[i][j]=k;
}
}
if(ret==INF) {puts("No solution."); return 0;}
for(int i=0;i<path.size();i++)
printf("%d ",path[i]);
return 0;
}
注意:
- 初始化的时候d[i][i]要赋值为0
- 涉及到inf运算的时候 有可能会爆int 因此要开longlong
技巧:
floyd算法考虑最大这一个性质
只枚举相邻的点

浙公网安备 33010602011771号