UVa 10600 - ACM Contest and Blackout

题目:计算一个图的最小生成树和次小生成树。

分析:图论,最小生成树。冤家题(⊙_⊙),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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值