mst(次小生成树)


 
 
Time Limit: 1sec    Memory Limit:256MB
Description
Given a connected and undirected graph, a spanning tree of that graph is a subgraph that is a tree and connects all the
 vertices together. A single graph can have many different spanning trees.  We can also assign a weight to each edge,
 and use this to assign a weight to a spanning tree by computing the sum of the weights of the edges in that spanning tree.
 A minimum spanning tree (MST) is a spanning tree with weight less than or equal to the weight of every other spanning tree, 
and the second minimum spanning tree is a spanning tree with weight strict more than the weight of minimum spanning tree.
    Given a connected and undirected graph, you should calculate the weight of second minimum spanning tree.
Input
 The first line contain an integer T(1 <= T <= 10), indicate the number of testcase.
    For each testcase, the first line contain two numbers n, m(1<=n<=500, n - 1 <= m <= 1000), indicate the number of vertices 
and edges. The next m lines, ecah contain 3 numbers x, y, l(1<=x,y<=n, x != y, 1 <= l <= 1000000), indicate an undirected 
edge connect x and y with length l. There are no two edge connected the same vertices. 
 
Output

 For each testcase, print the weight of the second minimum spanning tree if exists, otherwise print -1.


题目来自移动信息工程学院短码之美月赛02


这道题要求次小生成树,假设最小生成树为T,其实T与次小生成树的区别就是一条T的边被一条T之外的边所替代了,所以对每一条T之外的边,比如这条边为E(a,b),在T中,a到b只有唯一一条路,那么加上E(a,b)能够组成回路,也就是说我们删掉T中的a到b的任意一条边节点还是联通的,所以我们只需要在T中找到a和b之间最长的那条边,把它替换掉。在不断地替换中找到次最小生成树。

#include <bits/stdc++.h>
#define MAX 1E9 
using namespace std ;

int n,m;
int MAP[502][502];
int maxn[502][502] ; 					
int pre[502] ;                        
bool visit[502] ;
int Prim()
{
	int sum=0 ;
	visit[1]=true ;
	for(int i=1; i<n; i++)
	{
		int Min=1;
		for(int j=2;j<=n;j++)
			if(!visit[j]&&MAP[Min][0]>MAP[j][0])
			   Min=j ; 
			   
		sum+=MAP[Min][0] ;

		//算法的关键,maxn[j][Min]代表j与Min间最长的一条边
		for(int j=1;j<=n;j++)
			if(visit[j]){
			  maxn[j][Min]=max(maxn[j][pre[Min]],MAP[Min][0]);
			  maxn[Min][j]=maxn[j][Min];
			}
		visit[Min]=true ;
		
		for(int j=1; j<=n; j++)
			if(!visit[j]&&MAP[j][Min]<MAP[j][0]){
				MAP[j][0]=MAP[j][Min] ;
				pre[j]=Min ;
			}	
	}
	return sum;
}

int SecondMST()
{

//这里 pre[i]!=j && pre[j]!=i 说明E(i,j)不属于最小生成树 
	int sum=Prim();
	int a=MAX ;
	for(int i=1; i<=n; i++)
	  for(int j=1; j<=n; j++)
	  
		if(i!=j && pre[i]!=j && pre[j]!=i)			 
		    if(a>sum-maxn[i][j]+MAP[i][j]&&(sum-maxn[i][j]+MAP[i][j]>sum)&&MAP[i][j]<MAX)
				a=sum-maxn[i][j]+MAP[i][j];	
	return a; 
}
int main()
{
	int t;
	scanf("%d", &t) ;
	while(t--)
	{
		scanf("%d%d", &n, &m) ;
		for(int i=0; i<=n; i++)
			for(int j=0; j<=n; j++){
				MAP[i][j]=MAX;
				maxn[i][j]=0;
			}
		int a,b,val;		 
		for(int i=0; i<m; i++){
			scanf("%d%d%d",&a,&b,&val) ;
			MAP[a][b]=MAP[b][a]=val ;
		}
		// 初始化条件,前导都是1,map[x][0]用来保存从已经完成的生成树到x的最短边 
		for(int i=1; i<=n; i++){
			visit[i]=0;
			pre[i]=1;
			MAP[i][0]=MAP[i][1] ;
		}
		if(m==n-1)
		printf("-1\n");
		else
		printf("%d\n",SecondMST());
	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值