Before learning disjoint-set, you first need to understand the basic disjoint-set functions can be completed. Disjoint-set is mainly used to deal with the issue of merger disjoint sets. It is a basic algorithm, discrete mathematics, and can be used to check the connected components of a graph set requirements, this feature can use it to solve a series of problems for us, for example hdu1232 "Smooth Traffic Project" and so on. Here we use to understand the basics of this question and search sets.
Before explaining the topic, first look at the disjoint-set. Disjoint-set is a series of elements in accordance with the title given correlation between them into a disjoint set. Specific steps are found on behalf of the two elements of the current element (typically disjoint-set relationship between the two elements is determined) (each symbol is representative of elements of a set, a collection set is different from other causes each represent different element). If the two representatives of the different elements of the set before the two are different, but because of the relationship between these two elements, the collection will be where these two elements are combined into a set, but before the two elements of each set of instructions on behalf of the yuan yuan representatives will be merged into one, because the two have merged into a collection of collections, a collection of only one representative of yuan; if both are in the same collection, the collection will be no merger, consolidation behalf yuan A step of. In the final only need to determine how many representatives yuan, you can know how many disjoint sets, that is, how many discrete mathematics connected components. See this, zero-based might not understand, it does not matter, to explain by following this question.
hdu1232 "Smooth Traffic Project": http: //acm.hdu.edu.cn/showproblem.php pid = 1232?
Note: number of roads may be communicated between the two cities, ie
. 3. 3
. 1 2
. 1 2
2. 1
This input is valid
when N is 0, an input end, the use cases are not processed.
#include<bits/stdc++.h>
#define maxn 1000+5
using namespace std;
int s[maxn]={0};
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;
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);
s[x]=s[y];
}
int find(int x)
{
int r=x;
while(r!=s[r])
r=s[r];
return r;
}
This code is displayed on the submission of hdu is 140ms, write code that can be said is the code of the most violent, almost not optimized. Then you explain an optimization, query optimization (path compression), the find function, to find r x represents the yuan, the need to find up step by step, although this would certainly be found, but once the amount of data too large, prone to the query path is too long, resulting in longer time each query, the query affect efficiency.
The left view is not optimized model before, right graph is the ideal state of query optimization performed.
The right to the left compared to just change the find function, to the following changes:
int find(int x)
{
int r=x;
while(r!=s[r]) r=s[r];
int i=x,j;
while(i!=r)
{
j=s[i];
s[i]=r;
i=j;
}
return r;
}
After such a path compression, on hdu1232 submitted with a time of 109ms, to enhance the efficiency of the display, mainly because of optimized queries.
In addition to query optimization, as well as the merger of optimization, but I feel combined optimization is really not too important, this optimization can be said with respect to the low rate of nearly optimized, so here only briefly about (the collection of small height and to the higher altitude of the set, to avoid increasing the height of the tree without the brain), and write down the relevant code:
#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倍之差。(在提交的过程中,发现有时即使是同一段代码,但是耗时竟然会有微小的差异,让我至今有些不太理解)