poj 1734 Sightseeing trip (Folyd求无向图最小环)

版权声明:转载请在原文附上源连接以及作者,谢谢~ https://blog.csdn.net/weixin_39778570/article/details/87877664

ACM题集:https://blog.csdn.net/weixin_39778570/article/details/83187443
图论:https://blog.csdn.net/weixin_39778570/article
题目链接:http://poj.org/problem?id=1734

题目描述

给定一幅无向图,求大于等于3条边的最小环的路径。

分析

可以使用Folyd算法,枚举到第k阶段时,更新答案 ans = min(ans, d[i][j] + a[j][k] + a[k][j]),
再更新Folyd方程,表示前1~k-1个城市从i到j (j>i)的最小距离 + 从j经过k回到i,由此形成环。(只枚举不大于k的节点,由对称性可知是正确的,因为先枚举了大于k的点故中转点k小于i,j,和之后枚举i,k中转点为j是一样的,前则多次枚举i,j后达到最优,后者枚举也是,但是显然后者枚举的次数更少)

Code
#include<cstdio>
#include<iostream> 
#include<cstring>
#include<algorithm>
#include<vector>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int N = 105;
int n,m,a[N][N],d[N][N],pos[N][N],ans=0x3f3f3f3f;
vector< int > Path;
void get_path(int x, int y){
	if(pos[x][y]==0)return;
	get_path(x, pos[x][y]);
	Path.push_back(pos[x][y]);
	get_path(pos[x][y], y);
} 
void solve(){
	memcpy(d,a,sizeof(d));
	for(int k=1; k<=n; k++){
		for(int i=1; i<k; i++){ // 不包含k点,作为i,j的媒介点 
			for(int j=i+1; j<k; j++){
				// 要装换成 long long 类型!!!,3个数相加 
				if(ans > (ll)d[i][j]+a[j][k]+a[k][i]){// i到j溜一遍,从j经过k回到i 
					ans = d[i][j]+a[j][k]+a[k][i];
					Path.clear();
					Path.push_back(i);
					get_path(i,j); // 此时i,j间还没考虑到k这个点 
					Path.push_back(j);
					Path.push_back(k); // 最后进过的点 
				}
			}
		}
		// folyd第k阶段
		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(ans==0x3f3f3f3f){
		puts("No solution.");
	}else{
		for(int i=0; i<Path.size(); i++){
			printf("%d ",Path[i]);
		}
		puts("");
	}
} 
int main(){
	scanf("%d%d",&n,&m);
	int x,y,z;
	memset(a,0x3f,sizeof(a));
	fo(i,1,n)a[i][i]=0;
	fo(i,1,m){
		scanf("%d%d%d",&x,&y,&z);
		a[x][y] = a[y][x]= min(a[x][y],z);
	}
	solve();	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_39778570/article/details/87877664