互いに素セットを学習する前に、まず基本的な互いに素セットの機能を完了することができます理解する必要があります。互いに素-セットは、主に合併ばらばらセットの問題に対処するために使用されます。これは、基本的なアルゴリズム、離散数学で、かつ、この機能は非常に上の例のhdu1232「円滑な交通プロジェクト」とのために、私たちのために一連の問題を解決するためにそれを使用することができ、グラフのセットの要件の連結成分をチェックするために使用することができます。ここでは、この質問と検索セットの基本を理解するために使用します。
トピックを説明する前に、ばらばらのセットを初めて目。互いに素なセットは、互いに素なセットにそれらの間の相関関係を指定されたタイトルに応じて、一連の要素です。具体的な手順は、現在の要素(典型的には2つの要素間の互いに素なセットの関係が決定される)(各シンボルは、集合の要素を表す、コレクションセットは他の原因は異なっているの二つの要素の代わりに見出されますそれぞれ)は、異なる要素を表します。2は異なっているが、これらの二つの要素がセットに統合されている場合ので、この2つの要素間の関係を、コレクションにはなりますが、命令の各セットの二つの要素の前に代わってもしセットの異なる要素の2人の代表の前に両方が同じコレクション内にある場合は、コレクションには、合併、統合代わっ元できなくなります; 2は、コレクションのコレクションに元の唯一の代表のコレクションを合併しているので、元の元代表は、一つにマージされます手順。最終的には唯一のあなたはどのように多くの互いに素な集合、つまり、コンポーネントを接続するどのように多くの離散数学で知ることができますどのように多くの代表の元、決定する必要があります。これを参照してください、ゼロベースの理解できないかもしれないが、この質問を、以下で説明する、重要ではありません。
hdu1232 "円滑な交通プロジェクト" します。http://acm.hdu.edu.cn/showproblem.php PID = 1232?
注:道路の数が2つの都市の間で通信することができる、すなわち、
3 3
1 2
1 2
2 1
この入力が有効である
Nが0である場合、入力端、ユースケースが処理されません。
#include <ビット/ STDC ++ H>
の#define MAXN + 5~1000
名前空間stdを使用。
INT S [MAXN] = {0}。
INTマージ(int型のx、int型のY)。
int型を見つける(int型x)は;
INTのmain()
{
int型N、M、X、Y。
一方、(1)
{
CIN >> N。
(!N)の場合ブレーク。
cinを>>メートル。
以下のために(INT i = 1; iが<= N; iは++)
Sを[I] = I。
以下のために(; I <= M I ++はi = 1からINT)
{
CIN >> X >> Y。
(x、y)をマージ。
}
int型の和= 0。
以下のために(iは++; iがn = <I 1は= INT)
IF(S [I] == I)合計++。
coutの<<合計-1 <<てendl;
}
0を返します。
}
int型のマージ(int型のx、int型のY)
{
X =検索(X)
Y =検索(Y)。
S [X] = sの[Y]。
}
int型の検索(INT X)
{
int型R = X。
(!= R sの[R])一方、
R = S [R]。
Rを返します。
}
このコードは、HDUの提出に表示されているほとんど最適化されていない、最も暴力のコードであると言うことができるコードを書く、140msのです。次に、これは確かに見られるが、R xは、元、ステップバイステップを見つける必要性を表し見つけるために最適化、クエリの最適化(パス圧縮)、検索機能を、説明しますが、データ量に一度、あまりにも大型、クエリのパスを受けやすいが、長い時間で各クエリを、その結果、長すぎる、クエリが効率に影響を与えます。
左の図は前モデルを最適化されていない、右のグラフが行われ、クエリの最適化の理想的な状態です。
ただ、次の変更に、検索機能を変更するに比べて左へ右:
int型の検索(int型x)は、
{
INTのR = X。
(!= R sの[R])一方、R = S [R]。
int型I = xで、J。
しばらく(I!= R)
{
Jが= S [i]は、
S [i]は= R。
私はjは=。
}
Rを返します。
}
このようなパス圧縮後、hdu1232に主に最適化されたクエリの表示の効率を高めるために、109msの時間と共に提出しました。
また、最適化だけでなく、最適化の合併を照会するために、私は小さな高さのコレクション(約だけで簡単にので、ここでは、組み合わせ最適化は、この最適化はほぼ最適化の低金利に関して言うことができ、本当にあまりにも重要ではありません感じますセットのより高い標高に、脳なしツリーの高さを増加させることを避けるために)、および関連するコードを書き留め。
#include<bits/stdc++.h>
#define maxn 1000+5
using namespace std;
int s[maxn]={0};
int height[maxn];
int merge(int x,int y);
int find(int x);
int main()
{
int n,m,x,y;
while(1)
{
cin>>n;
if(!n) break;
cin>>m;
for(int i=1;i<=n;i++)
{
s[i]=i;
height[i]=0;
}
for(int i=1;i<=m;i++)
{
cin>>x>>y;
merge(x,y);
}
int sum=0;
for(int i=1;i<=n;i++)
if(s[i]==i) sum++;
cout<<sum-1<<endl;
}
return 0;
}
int merge(int x,int y)
{
x=find(x);
y=find(y);
if(height[x]==height[y])
{
height[x]++;
s[y]=x;
}
else
{
if(height[x]<height[y]) s[x]=y;
else s[y]=x;
}
}
int find(int x)
{
int r=x;
while(r!=s[r])
r=s[r];
return r;
}
这样在hdu1232用时124ms;
不管我怎么优化,耗时一直在100ms开外,在提交列表中,有人可以15ms,31ms的通过,开始我以为是不是函数调用浪费时间,把这几个函数都写进main函数,利用for循环进行实现,不过这样看起来整个程序的条理性较低,不过幸好这道题比较简单,都写在main函数中也比较容易,但是提交之后耗时仍没什么大变化,最后再看看题发现在题后有这么一句话:Huge input, scanf is recommended.这是说这道题的输入量比较大,在scanf与cin优缺点比较中,scanf的输入较快,cin书写方便,但是做ACM,最好还是用scanf,如果最后因为输入的不同导致的超时,哭都来不及。改为scanf后,耗时15ms。两种输入将近10倍之差。(在提交的过程中,发现有时即使是同一段代码,但是耗时竟然会有微小的差异,让我至今有些不太理解)