图论 次小生成树

次小生成树

思路: 先求出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;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值