互いに素-セットエントリ(hdu1232「円滑な交通プロジェクト」)

互いに素セットを学習する前に、まず基本的な互いに素セットの機能を完了することができます理解する必要があります。互いに素-セットは、主に合併ばらばらセットの問題に対処するために使用されます。これは、基本的なアルゴリズム、離散数学で、かつ、この機能は非常に上の例のhdu1232「円滑な交通プロジェクト」とのために、私たちのために一連の問題を解決するためにそれを使用することができ、グラフのセットの要件の連結成分をチェックするために使用することができます。ここでは、この質問と検索セットの基本を理解するために使用します。

トピックを説明する前に、ばらばらのセットを初めて目。互いに素なセットは、互いに素なセットにそれらの間の相関関係を指定されたタイトルに応じて、一連の要素です。具体的な手順は、現在の要素(典型的には2つの要素間の互いに素なセットの関係が決定される)(各シンボルは、集合の要素を表す、コレクションセットは他の原因は異なっているの二つの要素の代わりに見出されますそれぞれ)は、異なる要素を表します。2は異なっているが、これらの二つの要素がセットに統合されている場合ので、この2つの要素間の関係を、コレクションにはなりますが、命令の各セットの二つの要素の前に代わってもしセットの異なる要素の2人の代表の前に両方が同じコレクション内にある場合は、コレクションには、合併、統合代わっ元できなくなります; 2は、コレクションのコレクションに元の唯一の代表のコレクションを合併しているので、元の元代表は、一つにマージされます手順。最終的には唯一のあなたはどのように多くの互いに素な集合、つまり、コンポーネントを接続するどのように多くの離散数学で知ることができますどのように多くの代表の元、決定する必要があります。これを参照してください、ゼロベースの理解できないかもしれないが、この質問を、以下で説明する、重要ではありません。

hdu1232 "円滑な交通プロジェクト" します。http://acm.hdu.edu.cn/showproblem.php PID = 1232?

問題の説明
既存のテーブルを取得するための都市交通の地方の調査では、都市部の道路は、テーブルには、都市や町に直接接続された各道路を示しています。ターゲット州政府「円滑な交通プロジェクト」(あなたが道路を介して間接的に相互に到達できる限り、必ずしも直接道路に接続していない)任意の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
 
巨大な入力は、scanfのが推奨されます。
この質問は、少なくとも、つまり、道路が構築されたコンポーネントマイナス1を接続する枝の数を確認しようとしている、ばらばらのセットの古典的な問題です。
この時点で、彼らは徐々にコレクションの数を減らし、入力の町の間の関係として、因果関係を確立していないので、ないときは、入力接続関係の町の最初のステップは、すべての町は、別々のコレクションとして考えているはずです。
以下のために(INT i = 1; iが<= N; iは++します)
    S [i]は= I。
このサイクルだけでなく、n個のセットの確立、およびドルの代表のセットを決定する方法を示唆し、それは、S [i]が== I、iは、元の表現場合のみです。
次のxyの入力では、XY間の道路がある意味、xyがコレクション内です。
空のget(int型のx、int型のY)
{
    X =検索(X); //要素xの代表的なセットを見つけ、値xに割り当て
    Y =検索(Y)。
    S [X] = sの[Y]; //は(たとえ前に既に設定されたXYが、このステップは影響されない)は、2つの要素のXYの代表的なセットをマージ
}
int型のfind(int型x)は//関数を見つけるのコレクション要素どこに戻り引数の役割を表現することです
{
    一方、(X!= S [X])
        X = S [X]。
    Xを返します。
}
 
この単純な基本的な問題の前工程の後に解決し、最終的にのみその数から1を引いたものが、所望されていることを相互に排他的なセットは、存在するどのように多くの代表要素、すなわち、どのくらい決定することができます。
int型の合計= 0;
以下のために(INT i = 1; iが<= N; iは++します)
    IF(S [I] == I)合計++。
次のように要約すると、ACコードのこの質問は次のとおりです。

#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倍之差。(在提交的过程中,发现有时即使是同一段代码,但是耗时竟然会有微小的差异,让我至今有些不太理解)

おすすめ

転載: www.cnblogs.com/sunjianzhao/p/11294156.html