Disjoint-set entry (hdu1232 "Smooth Traffic Project")

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?

Problem Description
A provincial survey of urban traffic, urban roads to get existing tables, the table lists the cities and towns each road directly connected. Target provincial government "Smooth Traffic Project" is to make the province between any two towns can implement traffic (but not necessarily directly connected to the road, as long as you can reach each other indirectly through road). Minimum asked how many roads also need to build?
 
Input
Test input contains several test cases. Each test case is given row of the first two positive integers, are the number of towns N (<1000) and road number M; M rows corresponding to the next M path, each row is given a pair of positive integers, respectively, the number two towns in direct communication path. For simplicity, the town numbered from 1 to N.
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.
 
Output
For each test case, the number of roads in at least one line in the output needed construction.
 
Sample Input
4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0
 
Sample Output
1
0
2
998
 
Huge input, scanf is recommended.
This question is seeking at least to see the road built, that is, the number of branches connected components minus one, is the classic problem of disjoint-set.
The first step in when not input connection relation town, every town should have considered as a separate collection, because at this time they have not established a causal relationship, as the relationship between the input town, gradually reduce the number of collections.
for(int i=1;i<=n;i++)
    s[i]=i;
This cycle not only the establishment of a set of n, and suggests how to determine a set of representatives of dollars, and that is only if s [i] == i, i, represented yuan.
With the input of the next xy, meaning there is a road between xy, xy is a collection within.
void get (int x, int y)
{
    x = find (x); // find where the representative set of element x, and assign it to the value x
    y=find(y);
    s [x] = s [y]; // merge the representative set of two element xy (already a set xy even before, but this step is not affected)
}
int find (int x) // find function is to represent the role of return argument at the collection element where
{
    while(x!=s[x])
        x=s[x];
    return x;
}
 
After the previous step of this simple basic problem can be solved, and finally only determines how many representatives element, i.e. how much there is a set of mutually exclusive, that their number minus one is also desired.
int sum=0;
for(int i=1;i<=n;i++)
    if(s[i]==i) sum++;
In summary, this question of the AC code is as follows:

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

Guess you like

Origin www.cnblogs.com/sunjianzhao/p/11294156.html