次小生成树 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数组来记录的,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【1】项目代码完整且功能都验证ok,确保稳定可靠运行后才上传。欢迎下载使用!在使用过程中,如有问题或建议,请及时私信沟通,帮助解答。 【2】项目主要针对各个计算机相关专业,包括计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网等领域的在校学生、专业教师或企业员工使用。 【3】项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 【4】如果基础还行,或热爱钻研,可基于此项目进行二次开发,DIY其他不同功能,欢迎交流学习。 【注意】 项目下载解压后,项目名字和项目路径不要用中文,否则可能会出现解析不了的错误,建议解压重命名为英文名字后再运行!有问题私信沟通,祝顺利! 基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值