您的位置:首页 > 其它

UVa 10600 - ACM Contest and Blackout

2014-03-22 15:34 393 查看
题目:计算一个图的最小生成树和次小生成树。

分析:图论,最小生成树。冤家题(⊙_⊙),2011年北京赛区现场赛A题类似物。

当时在赛场上想到了kruskal+bfs的加边删边算法。由于写错了一行代码最后悲剧了。

利用kruskal算法先计算出最小生成树,然后设置maxe[i][j]数组,

记录i到j在最小生成树上的路径中的最长边,这个计算利用bfs是O(|V|)的(|E|=|V|-1)

然后遍历所有的边如果不是smt上的边,就加进去,减掉这个环上的其它边中最长的,即maxe

更新判断,取出最小值即为次小生成树。T = O(|V|*|V|+|E|)=O(|V|*|V|)

方法2,利用prim算法,计算maxe的过程和节点更新过程相似,可同时进行,处理简单。T =(|V|*|V|)

方法3,遍历每条边,然后扫描所有不在smt上的边,求解,找到最小即可,可能TLE。T = O(|E|*|V|)

注意:(⊙_⊙)都是眼泪( ⊙ o ⊙ )啊!

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>

using namespace std;

typedef struct d_node
{
	int point1;
	int point2;
	int weight;
}enode;
enode edge[5005];
int   ismt[5005];

//link
typedef struct l_node {
	int 	point;
	int     weight;
	l_node *next;
}lnode;
lnode *l_head[101];
lnode  l_node[20002];

int  l_count;

void link_inital()
{
	l_count = 0;
	memset( l_head, 0, sizeof(l_head) );
}

void link_add( int a, int b, int c )
{
	l_node[l_count].point = b;
	l_node[l_count].weight = c;
	l_node[l_count].next = l_head[a];
	l_head[a] = &l_node[l_count ++];
}
//end_link

//union_set
int sets[101];
int rank[101];

void set_inital( int a, int b )
{
	for ( int i = a ; i <= b ; ++ i ) {
		rank[i] = 0;
		sets[i] = i;
	}
}

int  set_find( int a )
{
	if ( a != sets[a] )
		sets[a] = set_find( sets[a] );
	return sets[a];
}

void set_union( int a, int b )
{
	if ( rank[a] < rank[b] )
		sets[a] = b;
	else {
		if ( rank[a] == rank[b] )
			rank[a] ++;
		sets[b] = a;
	}
}
//end_union_set

int cmp_e( enode a, enode b )
{
	return a.weight < b.weight;
}

int kruskal( int n, int m )
{
	memset( ismt, 0, sizeof(ismt) );
	sort( edge, edge+m, cmp_e );
	
	set_inital( 1, n );
	int sum = 0;
	for ( int i = 0 ; i < m ; ++ i ) {
		int A = set_find( edge[i].point1 );
		int B = set_find( edge[i].point2 );
		if ( A != B ) {
			set_union( A, B );
			ismt[i] = 1;
			sum += edge[i].weight;
		}
	}
	return sum;
}

int  maxe[101][101];
int  smap[101][101];
int  used[101];
int  queue[101];

void bfs( int s )
{
	memset( used, 0, sizeof(used) );
	used[s] = 1;
	queue[0] = s;
	for ( int move = 0,save = 1 ; move < save ; ++ move ) {
		int now = queue[move];
		for ( lnode* p = l_head[now] ; p ; p = p->next )
			if ( !used[p->point] ) {
				used[p->point] = 1;
				maxe[s][p->point] = max( maxe[s][now], p->weight );
				queue[save ++] = p->point;
			}
	}
}

int main()
{
	int t,n,m,a,b,c;
	while ( scanf("%d",&t) != EOF ) 
	while ( t -- ) {
		scanf("%d%d",&n,&m);
		link_inital();
		for ( int i = 0 ; i < m ; ++ i ) {
			scanf("%d%d%d",&a,&b,&c);
			edge[i].point1 = a;
			edge[i].point2 = b;
			edge[i].weight = c;
		}
		
		int k = kruskal( n, m );
		for ( int i = 0 ; i < m ; ++ i )
			if ( ismt[i] ) {
				link_add( edge[i].point1, edge[i].point2, edge[i].weight );
				link_add( edge[i].point2, edge[i].point1, edge[i].weight );
			}
		memset( maxe, 0, sizeof(maxe) );
		for ( int i = 1 ; i <= n ; ++ i )
			bfs( i );
		
		int Max = 300003,p1,p2;
		for ( int i = 0 ; i < m ; ++ i ) {
			p1 = edge[i].point1;
			p2 = edge[i].point2;
			if ( !ismt[i] && Max > k+edge[i].weight-maxe[p1][p2] )
				Max = k+edge[i].weight-maxe[p1][p2];
		}
		
		printf("%d %d\n",k,Max);
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: