USACO 4.1 Fence Loops 最小环

http://ace.delos.com/usacoprob2?a=b8o6p9MDlbr&S=fence6

题意:给你一个有N个点的图,求图中的最小环。N<=100

思路:算法很简单,就是一个O(N^3)的Floyd最小环。这道题目恶心的地方是给你的图的信息是图中一些边与边之间依附的信息,这样就给建图带来了麻烦。没有想到好的方法,用了一种比较笨的方法,先将每条线段看做一条独立的边(有两个独立的顶点),然后依次枚举每条边的两个顶点,将与之有交点的边的顶点用并查集合并在一起,有该并查集的根作为这些顶点的代表结点,这时候其他的顶点就可以不去考虑了,只要考虑这个代表元就可以了,最后建好图之后跑一次Floyd就可以了。复杂度为:O(N^3)。 


代码:

/*
ID : chris
LANG :C++
TASK : fence6
*/
#include<stdio.h>
#include<string.h>
const int inf = (1<<28) ;
int N ;
int data[105][2][10] ;
int len[105] ,cnt;
int maze[210][210] ;
int p[210] ;
int num[110] ;

int find(int a){
	if( p[a] != a ){
		p[a] = find( p[a] ) ;
	}
	return p[a] ;
}

void Union(int a, int b){
	int fa = find(a) ;
	int fb = find(b) ;
	if(fa > fb){
		p[fa] = fb ;
	}
	else if(fa < fb){
		p[fb] = fa ;
	}
}
int dis[210][210] ;
int map[210][210] ;
int M ;
bool vis[210] ;

void solve(){
	for(int i=1;i<=2*N;i++){
		for(int j=1;j<=2*N;j++){
			if(i == j)	dis[i][j] = 0 ;
			else		dis[i][j] = inf ;
		}
	}	
	for(int i=1;i<=2*N;i++){
		for(int j=1;j<=2*N;j++){
			int a = find(i) ;
			int b = find(j) ;
			dis[a][b] = dis[b][a] = maze[a][b] ;
		}
	}
	int _min = inf ;
	for(int k=1;k<=2*N;k++){
		for(int i=1;i<k;i++){
			for(int j=i+1;j<k;j++){
				if( _min > dis[i][j] + maze[k][i] + maze[k][j] ){
					_min = dis[i][j] + maze[k][i] + maze[k][j] ;
				}
			}
		}
		for(int i=1;i<=2*N;i++){
			for(int j=1;j<=2*N;j++){
				if(dis[i][j] > dis[i][k] + dis[k][j] ){
					dis[i][j] = dis[i][k] + dis[k][j] ;
				}
			}
		}	
	}
	printf("%d\n",_min);
}
int main(){
	freopen("fence6.in","r",stdin);
	freopen("fence6.out","w",stdout);
	int a ,b,c,d ;
	while(scanf("%d",&N) == 1){
		for(int i=1;i<=2*N;i++){
			for(int j=0;j<210;j++){
				if(i == j)	maze[i][j] = 0 ;
				else		maze[i][j] = inf ;
			}
			p[i] = i ;
		}
		for(int i=0;i<N;i++){
			scanf("%d",&a);
			num[i] = a ;
			scanf("%d %d %d",&len[a],&c,&d);
			data[a][0][0] = c ;
			data[a][1][0] = d ;
			for(int j=1;j<=c;j++){
				scanf("%d",&data[a][0][j]);
			}
			for(int j=1;j<=d;j++){
				scanf("%d",&data[a][1][j]);
			}
		}
		
		for(int i=0;i<N;i++){
			a = num[i] ;
			for(int j=1;j<=data[a][0][0];j++){
				int v = data[a][0][j] ;
				int ans = -1;
				for(int k=1;k<=data[v][0][0];k++){
					if(a == data[v][0][k]){
						ans = 2 * v - 1;	break ;
					}
				}	
				if(ans == -1){
					ans = 2 * v ;	
				}
				Union(2*a-1,ans);
			}
			for(int j=1;j<=data[a][1][0];j++){
				int v = data[a][1][j] ;
				int ans = -1 ;
				for(int k=1;k<=data[v][0][0];k++){
					if(a == data[v][0][k]){
						ans = 2 * v - 1;	break ;
					}
				}
				if(ans == -1)	ans = 2 * v  ;
				Union(2*a,ans);
			}
		}
		for(int i=0;i<N;i++){
			c = num[i] ;	
			int a = find(2*c-1) ;
			int b = find(2*c) ;
			maze[a][b] = maze[b][a] = len[c] ;
		}
		
		solve() ;
	}
	return 0 ;
}


你可能感兴趣的:(USACO 4.1 Fence Loops 最小环)