次小生成树 poj1679

次小生成树 poj1679

遇到一道需要思考的题,所以把他写下来,见代码注释

#include<stdio.h>
#include<iostream>
#include<queue>//什么是最小生成树?简单说就是第二小的树,这个第二小不一定是总权值第二小,也可能和MST一样的
#include<stack>//题目:判断最小生成树是否唯一 
#include<vector> //开始的时候 用的另一种枚举但是有个细节没处理掉 就错了 
#include<string.h>//最小生成树 运用的一个重要结论就是  
#include<math.h> //次小生成树就是最小生成树的一条边替换成另一条不在最小生成树的边 也就是只换一条就行 
#include<algorithm>//而且其他的边不变;这个结论不是很懂 给不出证明 
#define inf 0x3f3f3f3f
const double INF=0x3f3f3f3f;
const int max_n=105;
using namespace std;
int n,m;
int dist[max_n],maps[max_n][max_n],past[max_n],maxb[max_n][max_n];
bool bian[max_n][max_n];
void init()
{
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			maps[i][j]=inf;//其他的设为无穷大 
}
int prim(int src)
{
	int u;int ans=0;
	bool ins[max_n];
	memset(ins,false,sizeof(ins));//一定要赋初始值 记住啊  错了好几回了 
	memset(bian,false,sizeof(bian));//标记边是否在MST中 
	memset(maxb,-1,sizeof(maxb));//记录i到j的最大边 
	for(int i=1;i<=n;i++){
		dist[i]=maps[src][i];//初始原点到其他点的距离
		if(i!=src)
			past[i]=src;
	}
	ins[src]=1;past[src]=-1;
	for(int i=1;i<n;i++)//1~n直接就是算全部 原点是零 所以这里能选出来 如果出现的负值边的话 就不能了 
	{
		int mindst=inf;u=-1;
		for(int i=1;i<=n;i++)
			if(!ins[i] && dist[i]<mindst)
				mindst=dist[i],u=i;
		if(u==-1)	return -1;//这个就是不联通 
		ans+=mindst;//加权边 
		ins[u]=1;//加入 
		bian[u][past[u]]=bian[past[u]][u]=true;
		for(int i=1;i<=n;i++)
		{
			if(ins[i])maxb[u][i]=maxb[i][u]=max(maxb[i][past[u]],dist[u]);//更新i到u的最大边 就是 i到past[u] 与dist[u]看哪个大 
			if(!ins[i]&&dist[i]>maps[u][i])//dijkstra与prim不同之处就在于更新的这个地方 
			{
				dist[i]=maps[u][i];//dijkstra更新是更新点到整个树的距离 而prim是更新节点之间的距离
				past[i]=u;
			}
		}
	}
	return ans;
}
int smst(int ans)
{
	int Min=inf;
	for(int i=1;i<n;i++)
		for(int j=i+1;j<=n;j++)
		{
			if(!bian[i][j] && maps[i][j]!=inf)
				Min=min(Min,ans-maxb[i][j]+maps[i][j]); 
		}
	return Min;
}
int main()
{
	int t,flag=0,x,y,data;
	scanf("%d",&t);
	while(t--)
	{ 
		scanf("%d%d",&n,&m);
		init();
		for(int i=0;i<m;i++)
		{
			scanf("%d%d%d",&x,&y,&data);
			maps[x][y]=maps[y][x]=data;
		}
		int ans=prim(1);
		if(ans==-1)
			printf("Not Unique!\n");
		else
		{
			if(ans==smst(ans))//次小生成树也可能等于最小生成树 
				printf("Not Unique!\n");
			else
				printf("%d\n",ans);
		}
	}
	return 0;
}

总结下 ,其实求次小生成树,利用那个重要结论:次小生成树/就是最小生成树中的一条边/替换成/另一条不属于最小生成树的边。也就是只换一条就行了,而且MST的其他的边不变;这个结论不是很懂 给不出证明;

那么怎么替换那条边?也就是遍历每一条不属于MST(最小生成树)的边,寻找最小的;

既然说是替换,那么就要删除MST的一条边,然后换成不属于MST的边;这样可能不理解

换句话说就是;在MST加一条边,那么就是n条边了,树中形成了一条环,显然是不行的,那么我们还要在环中删除一条边,那么我们怎么删除才能保证最小了?很显然不可能是删除刚刚加的那一边,因为删除了他就是MST,跟没删一样

,我们要保证权值尽量小,那么我们删除的边就尽量大,我用的是maxb数组来记录的,

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下 4载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值