次小生成树
思路: 先求出MST并记录其边,然后逐一标记MST的边为无穷大,依次求Prim找出小于第一次计算出的MST,并大于其它MST的权值,即为次小生成树。
时间复杂度: Prim为O(n2),MST有n-1个边,所以这个算法为O(n3)。
#include<iostream>
using namespace std;
#define NS 110
#define INF 0x7fffffff
int n , m;
int map[NS][NS];
bool visited[NS];
int dis[NS] , elen;
int _pre[NS];
struct Edge {
int u , v;
}edge[NS];
void Init() {
int i , j;
for( i = 1 ; i <= n ; ++i ) {
visited[i] = false;
for( j = 1 ; j <= n ; ++j ) {
map[i][j] = INF;
}
}
}
int Prim( bool sign ) {
int i , j;
int _min , k , min_ans;
for( i = 1 ; i <= n ; ++i ) {
dis[i] = map[1][i];
visited[i] = false;
_pre[i] = 1;
}
dis[1] = 0; visited[1] = true;
min_ans = 0;
for( i = 2 ; i <= n ; ++i ) {
_min = INF;
for( j = 1 ; j <= n ; ++j ) {
if( _min > dis[j] && !visited[j] ) {
_min = dis[j];
k = j;
}
}
if( _min == INF ){ return -1; } // Not connected
visited[k] = true;
min_ans += _min;
if( sign ) {
edge[elen].u = _pre[k];
edge[elen++].v = k;
}
for( j = 1 ; j <= n ; ++j ) {
if( !visited[j] && dis[j] > map[k][j] )
{ dis[j] = map[k][j]; _pre[j] = k; }
}
}
return min_ans;
}
int main() {
int t;
int i, u, v, w, fri_ans, sec_ans, tmp;
scanf( "%d" , &t );
while( t-- ) {
scanf( "%d %d" , &n , &m );
Init();
for( i = 0 ; i < m ; ++i ) {
scanf( "%d %d %d" , &u , &v , &w );
if( map[u][v] > w )
{ map[u][v] = map[v][u] = w; }
}
elen = 0;
fri_ans = Prim( true );
for( i = 0 ; i < elen ; ++i ) {
tmp = map[edge[i].u][edge[i].v];
map[edge[i].u][edge[i].v] = INF;
map[edge[i].v][edge[i].u] = INF;
sec_ans = Prim( false );
if( sec_ans == fri_ans )
{ printf( "Not Unique!\n" ); break; }
map[edge[i].u][edge[i].v] = tmp;
map[edge[i].v][edge[i].u] = tmp;
}
if( i >= elen )
{ printf( "%d\n" , fri_ans ); }
}
return 0;
}