トピック
ある州では、都市の交通状況を調査し、既存の都市道路の統計表を入手しました。この表には、各道路に直接接続されている市や町がリストされています。州政府の「ブロックされていないプロジェクト」の目標は、州内の任意の2つの町の間の交通を可能にすることです(ただし、道路を介して間接的に相互に到達できる限り、必ずしも道路で直接接続されている必要はありません)。少なくともいくつの道路を建設する必要があるか尋ねてください。
入力
テスト入力には、いくつかのテストケースが含まれています。各テストケースの最初の行は、町の数N(<1000)と道路の数Mの2つの正の整数を示します。後続のM行はMの道路に対応し、各行はそれぞれ正の整数のペアを示します。道路で直結している2つの町の数。簡単にするために、町には1からNまでの番号が付けられています。
注:2つの都市間に複数の道路が存在する可能性があるため、
3 3
1 2
1 2
2 1の入力
も有効です
。Nが0の場合、入力は終了し、ユースケースは処理されません。
出力
テストケースごとに、1行に建設する必要のある道路の最小数を出力します。
サンプル入力
4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0
サンプル出力
1
0
2
998
そしてチェックセット
複合検索には2つの機能があります。
- 2つの要素がセットに属しているかどうかを確認します
- 必要に応じて異なるコレクションを組み合わせる
ユニオン検索セットには、検索とマージの2つの操作があります。
ルックアップ:要素が属するセットを判別します。このステップでは、ルートノードが見つかるまで上向きに検索を続け、ルートノードが同じかどうかに応じて、2つの要素が同じセットに属しているかどうかを判断します。
たとえば、ここで点bと点eは同じルートcを持っているので、それらはセットに属します。
マージ:2つのサブコレクションを1つのコレクションに結合します。この手順では、1つのツリーを別のツリーのサブツリーとして使用し、2つのツリーをより大きなツリーにします。
2つのツリーをマージする場合、ツリーの高さが検索効率に影響するため、高さが低いツリーは常に高さが高いツリーのサブツリーとしてマージされます。高さの低いツリーは、高さの高いサブツリーとして使用されます。これにより、マージされたツリーの高さが増加せず、検索効率が向上します。
コード
主な機能:
検索:要素が属するサブセットを判別します。2つの要素が同じサブセットに属しているかどうかを判断するために使用できます。
ユニオン:2つのサブコレクションを同じコレクションに結合します。
#include <iostream>
using namespace std;
const int MAXN=1000;
int father[MAXN];
int height[MAXN];
void Initial(int n)
{
for(int i=0;i<n;++i)
{
father[i]=i;//初始时节点孤立,节点的父节点为本身
height[i]=0;//每个节点的高度为0
}
}
//查找根节点,或者说路径压缩
int Find(int x)
{
if(x!=father[x]){
father[x]=Find(father[x]);
}
return father[x];
}
//集合合并
void Union(int x,int y)
{
x=Find(x);
y=Find(y);
//x!=y说明这两个节点不在一个集合里面,由于现在给出了边(x,y),需要进行合并
if(x!=y)
{
if(height[x]>height[y]){
father[y]=x;
}
else if(height[x]<height[y]){
father[x]=y;
}
else{
father[x]=y;
++height[y];
}
}
}
int main()
{
int n,m;
while(cin>>n){
//n是城市数
if(n==0) break;
cin>>m;//m是道路的数量
Initial(n);//对每个城市节点初始化,初始每个城市都是孤立的
while(m--)
{
int x,y;
cin>>x>>y;
//读入已经建成的道路后,将道路连接城镇所在的集合合并
Union(x,y);
}
int number=-1;
for(int i=0;i<n;++i)
{
if(Find(i)==i) ++number;
}
cout<<number<<endl;//集合的数目应该是number+1,number记录的是还需要的道路数量
}
return 0;
}