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;
}

注意:

  1. 初始化的时候d[i][i]要赋值为0
  2. 涉及到inf运算的时候 有可能会爆int 因此要开longlong

技巧:
floyd算法考虑最大这一个性质
只枚举相邻的点

posted @ 2022-01-08 22:10  __iostream  阅读(38)  评论(0)    收藏  举报