poj 1679 《次小生成树的两种求法》

题目链接:poj 1679

两种方法的时间复杂度不同--

第一种好写--第二种时间复杂度小--

当m*n>>n*n时,为避免超时请用第二种


第一种以前写的:

时间复杂度为O(n*m);

思路是:先求出最小生产树--然后依次屏蔽一条边--重新求最小生成树...

每次时间需要m,一共求n次

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct nood
{
	int aa,bb,cc;
}bian[60000];
int fer[120];
int find(int xx)
{
	while (fer[xx]==xx)
	return xx;
	return fer[xx]=find(fer[xx]);
}
bool cmp(nood xx,nood yy)
{
	return xx.cc<yy.cc;
} 
int n,m;
int ks(int ii)
{
	for (int i=1;i<=n;i++)
	fer[i]=i;
	int ss=0,nn=1;
	for (int i=0;i<m;i++)
	{
		if (i==ii) continue;
		else if (find(bian[i].aa)!=find(bian[i].bb))
		{
			nn++;
			ss+=bian[i].cc;
			fer[find(bian[i].aa)]=find(bian[i].bb);
		}
	}
	
	if (nn!=n)
		ss=-1;
	return ss;
}
int main()
{
	int t;scanf("%d",&t);
	while (t--)
	{
		scanf("%d%d",&n,&m);
		for (int i=1;i<=n;i++)
			fer[i]=i;
		for (int i=0;i<m;i++)
			scanf("%d%d%d",&bian[i].aa,&bian[i].bb,&bian[i].cc);
		sort(bian,bian+m,cmp);
		int s=0;bool shu[12000];
		for (int i=0;i<m;i++)
			shu[i]=true;
		for (int i=0;i<m;i++)
		if (find(bian[i].aa)!=find(bian[i].bb))
		{
			shu[i]=false;
			s+=bian[i].cc;
			fer[find(bian[i].aa)]=find(bian[i].bb);
		}
		bool falg=true; 
		for (int i=0;i<m;i++)
		{
			if (shu[i]) continue;
			int p=ks(i);
			if (p==s)
			{
				falg=false;
				break;
			}
		}
		if (falg)
			printf("%d\n",s);
		else
			printf("Not Unique!\n");
	}
	return 0;
}



第二种方法:

求最小生成树时再用邻接表记录最小生成树中任意两点间的最长路---

然后加边删点---

时间复杂度为O(n*n);

时间大部分在更新两点间的最长路--

代码:

#include<cstdio> 
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
	int a,b;
	int w;
	bool select;
}edges[10020];
bool cmp(node xx,node yy)
{
	if (xx.w!=yy.w)
	return xx.w<yy.w;
	if (xx.a!=yy.a)
	return xx.a<yy.a;
	return xx.b<yy.b;
}
struct node1{
	int to;
	int next; 
}link[10020];
int n,m,il;
int head[120],end[120];
int length[120][120];
int fer[120];
int find(int xx)
{
	if (xx==fer[xx])
	return xx;
	return fer[xx]=find(fer[xx]);
}
void kruskal(node * edges,int n,int m)
{
	int k=0;
	for (il=1;il<=n;il++)
	{
		link[il].to=il;
		link[il].next=head[il];
		end[il]=il;
		head[il]=il;
	}
	sort(edges,edges+m,cmp);
	for (int i=0;i<m;i++)
	{
		if (k==n-1) break;
		int x=find(edges[i].a);
		int y=find(edges[i].b);
		if (x!=y)
		{
			for (int j=head[x];j!=-1;j=link[j].next)
			{
				for (int k=head[y];k!=-1;k=link[k].next)
				length[link[j].to][link[k].to]=length[link[k].to][link[j].to]=edges[i].w;
			}
			link[end[y]].next=head[x];
			end[y]=end[x];
			fer[x]=y;
			k++;
			edges[i].select=true;
		}
	}
}
int main()
{
	int t;scanf("%d",&t);
	while (t--)
	{
		scanf("%d%d",&n,&m);
		int x,y,z;
		for (int i=0;i<=n;i++)  
		{
			head[i]=-1;
			fer[i]=i;
		}
		for (int i=0;i<m;i++)
		{
			scanf("%d%d%d",&x,&y,&z);
			edges[i].a=x;edges[i].b=y;
			edges[i].w=z;
			edges[i].select=false;
		}
		int mst,mmst;
		kruskal(edges,n,m);
		mst=0;
		for (int i=0;i<m;i++)
		if (edges[i].select)
		mst+=edges[i].w;
		mmst=99999999;
		for (int i=0;i<m;i++)
		if (!edges[i].select)
		mmst=min(mst+edges[i].w-length[edges[i].a][edges[i].b],mmst);
	//	printf("%d   %d\n",mst,mmst);
		if (mst==mmst)
		printf("Not Unique!\n");
		else
		printf("%d\n",mst);
	}
	return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值