题解 洛谷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);
}
不要妄图追上西坠的太阳,而是要在黎明前就等着它!