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

ACM题集:https://blog.csdn.net/weixin_39778570/article/details/83187443
图论:https://blog.csdn.net/weixin_39778570/article/details/87825212
题目链接: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
#include 
#include
#include
#include
#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;
}

题目链接:https://vijos.org/p/1423
题意:求有向图进过1的最小环
分析:直接folyd求min(d[1][i]+d[i][1]),或者建立正反图,两边Dij求1到n个点的最短路,和n个点到1的最短路。

OJ挂了,未测

folyd

#include
#define ll long long 
#define fo(i,j,n) for(register int i=j; i<=n; ++i) 
using namespace std;
const int N=205, INF = 0x3f3f3f3f; // 弯道就是点
int n,m,d[N][N],t[N];
void folyd(){
	fo(k,1,n)
		fo(i,1,n)
			fo(j,1,n)
				d[i][j] = min(d[i][j], d[i][k]+d[k][j]);
	int ans = INF;
	fo(i,2,n)ans = min(ans, d[1][i]+d[i][1]);
	if(ans == INF)puts("-1");
	else printf("%d\n",ans);
} 
int main(){
	scanf("%d%d",&n,&m);
	memset(d,0x3f, sizeof(d));
	fo(i,1,n)scanf("%d",&t[i]);
	int x,y,z;
	fo(i,1,m){
		scanf("%d%d%d",&x,&y,&z);
		d[x][y] = min(d[x][y], z+t[x]);	
	}
	folyd();	
	return 0;
}
Dijkstra
#include
#define ll long long 
#define fo(i,j,n) for(register int i=j; i<=n; ++i) 
using namespace std;
const int N=205, M = 200005, INF = 0x3f3f3f3f; // 弯道就是点
int n,m,t[N],d[N],fd[N],g[N][N],fg[N][N];
int head[N], Next[M], ver[M], edge[M], tot;
int fhead[N], fNext[M], fver[M], fedge[M], ftot;
priority_queue<pair<int, int> > q,fq;
bool v[N];
void add(int x, int y, int z){
	ver[++tot]=y, edge[tot]=z;
	Next[tot]=head[x], head[x]=tot;
}
void fadd(int x, int y, int z){
	fver[++ftot]=y, fedge[ftot]=z;
	fNext[ftot]=fhead[x], fhead[x]=ftot;
}
void Dijkstra(int st){
	memset(v, 0, sizeof(v));
	memset(d, 0x3f, sizeof(d));
	q.push(make_pair(0,st));
	d[st]=0;
	while(q.size()){
		int x = q.top().second;q.pop();
		if(v[x])continue;
		v[x] = 1;
		for(int i=head[x]; i; i=Next[i]){
			int y = ver[i], wei = edge[i];
			if(d[y] > d[x]+wei){
				d[y] = d[x]+wei;
				q.push({-d[y],y});
			}
		} 
	}
}
void fDijkstra(int st){
	memset(v, 0, sizeof(v));
	memset(fd, 0x3f, sizeof(fd));
	fq.push(make_pair(0,st));
	fd[st]=0;
	while(fq.size()){
		int x = fq.top().second;fq.pop();
		if(v[x])continue;
		v[x] = 1;
		for(int i=fhead[x]; i; i=fNext[i]){
			int y = fver[i], wei = fedge[i];
			if(fd[y] > fd[x]+wei){
				fd[y] = fd[x]+wei;
				q.push({-fd[y],y});
			}
		} 
	}
}
int main(){
	scanf("%d%d",&n,&m);
	memset(g,0x3f, sizeof(g));
	memset(fg,0x3f, sizeof(fg));
	fo(i,1,n)scanf("%d",&t[i]);
	int x,y,z;
	fo(i,1,m){
		scanf("%d%d%d",&x,&y,&z);
		g[x][y]=min(g[x][y],z+t[x]);
		fg[y][x]=min(fg[y][x],z+t[x]);
	}
	fo(i,1,n){
		fo(j,1,n){
			if(g[i][j]!=INF)add(i,j,g[i][j]);
			if(fg[i][j]!=INF)fadd(i,j,fg[i][j]);
		}
	}
	Dijkstra(1);
	fDijkstra(1);
	int ans = INF;
	fo(i,2,n)
		ans = min(ans, d[i]+fd[i]);
	if(ans==INF)puts("-1");
	else printf("%d\n",ans);	
	return 0;
}

你可能感兴趣的:(poj)