题解 洛谷P2330 【[SCOI2005]繁忙的都市】

\[\huge\mathcal{DESCRIPTION} \]

日期 2020年8月22日
编号 洛谷\(\texttt{2330}\)
算法 并查集二分答案
来源 四川\(\texttt{2005}\)年省选

\[\huge\mathcal{SOLUTION} \]

这道题目我们容易考虑到两种算法。

  • 第一种:我们进行二分答案,每次\(\mathbb{CHECK}\)时使用并查集判断图的联通性。
  • 第二种:我们跑\(\mathbb{KRUSCAL}\),做最小生成树

我先想到了第一种算法,于是我就按照第一种方法做的。
具体讲一下细节吧~
首先,题目要求输出我们连了多少条边,因为是最小生成树,所以一定是点数减一。
其次,我们需要用并查集看是否连通,这是比较简单的,我们每次找边权小于二分值的边加进来即可。

\[\huge\mathcal{CODE} \]

#include<bits/stdc++.h>
using namespace std;
struct Struct
{
	long long From;
	long long To;
	long long Cost;
};
long long TotalPoint,TotalEdge;
Struct Edge[100001];
long long Fa[301];
inline long long Find(long long X);
inline bool Check(long long X);
int main(void)
{
	register long long i;
	cin>>TotalPoint>>TotalEdge;
	register long long Left,Right;
	Left=2147483647,Right=-1;
	for(i=1;i<=TotalEdge;i++)
	{
		cin>>Edge[i].From>>Edge[i].To>>Edge[i].Cost;
		Left=min(Left,Edge[i].Cost);
		Right=max(Right,Edge[i].Cost);
	}
	while(Left<Right)
	{
		register long long Middle;
		Middle=(Left+Right)/2;
		if(Check(Middle))
		{
			Right=Middle;
		}
		else
		{
			Left=Middle+1;
		}
	}
	register long long Ans=0;
	for(i=1;i<=TotalEdge;i++)
	{
		if(Edge[i].Cost<=Left)
		{
			Ans++;
		}
	}
	cout<<TotalPoint-1<<' '<<Left<<endl;
	return 0;
}
inline long long Find(long long X)
{
	return X==Fa[X]?X:Fa[X]=Find(Fa[X]);
}
inline bool Check(long long X)
{
	register long long i;
	for(i=1;i<=TotalPoint;i++)
	{
		Fa[i]=i;
	}
	for(i=1;i<=TotalEdge;i++)
	{
		if(Edge[i].Cost<=X)
		{
			Fa[Find(Edge[i].From)]=Find(Edge[i].To);
		}
	}
	register long long Ans;
	Ans=0;
	for(i=1;i<=TotalPoint;i++)
	{
		if(Fa[i]==i)
		{
			Ans++;
		}
	}
	return (Ans==1);
}
posted @ 2020-08-22 22:28  Bushuai_Tang  阅读(91)  评论(0编辑  收藏  举报