题目:计算一个图的最小生成树和次小生成树。
分析:图论,最小生成树。冤家题(⊙_⊙),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;
}