HDU-1213-How Many Tables
这是一道并查集模板题。
原先已经写过并查集3遍了。。但是一直没有整理。一直不写一直忘。吸取经验复习复习!
实实在在的模板题。
mix()合并
init()初始化
find()查找。
一看就懂emm
还是出现了问题。在mix()函数中合并的时候只把子结点的父亲改变了,没有改变子结点的父亲的父亲结点。。emmm
时间复杂度O(N)。树的长度。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
int fa[N];
int n, m;
void init()
{
for (int i = 1; i <= n; i++)
{
fa[i] = i;
}
}
int find(int x)
{
return fa[x] == x ? x : find(fa[x]);
}
void mix(int x, int y)
{
int xx = find(x);
int yy = find(y);
if (xx != yy)
{
fa[yy] = xx;
}
}
int main()
{
int t;
cin >> t;
while (t--)
{
int ans = 0;
cin >> n >> m;
init();
for (int i = 1; i <= m; i++)
{
int t1, t2;
cin >> t1 >> t2;
mix(t1, t2);
}
for (int i = 1; i <= n; i++)
{
int res = find(i);
if (res == i)
{
ans++;
}
}
cout << ans << endl;
}
return 0;
}
下面介绍合并优化代码,减少时间复杂度。
我们记录每棵树的高度。h[]记录
初始化为0
找到每个结点的根节点。直接将根节点合并
小树合并到大数中,可以减少树的高度。
如果树的高度相同,随便合并即可。
代码部分:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
int fa[N];
int h[N];
int n, m;
void init()
{
for (int i = 1; i <= n; i++)
{
fa[i] = i;
h[i] = 0;
}
}
int find(int x)
{
return fa[x] == x ? x : find(fa[x]);
}
void mix(int x, int y)
{
int xx = find(x);
int yy = find(y);
if (h[xx] == h[yy])
{
h[x]++;
fa[yy] = xx;
}
else
{
if (h[xx] < h[yy])
{
fa[xx] = yy;
}
else
{
fa[yy] = xx;
}
}
}
int main()
{
int t;
cin >> t;
while (t--)
{
int ans = 0;
cin >> n >> m;
init();
for (int i = 1; i <= m; i++)
{
int t1, t2;
cin >> t1 >> t2;
mix(t1, t2);
}
for (int i = 1; i <= n; i++)
{
int res = find(i);
if (res == i)
{
ans++;
}
}
cout << ans << endl;
}
return 0;
}
查询优化——路径压缩
find()函数在查找根节点的时候,路径可能很长。所以我们在返回的同时把i的所属父结点直接改成根节点。下次搜索O(1)时间可以解决。合并部分也被优化了。(合并部分也有查询)
代码部分:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
int fa[N];
int h[N];
int n, m;
void init()
{
for (int i = 1; i <= n; i++)
{
fa[i] = i;
h[i] = 0;
}
}
int find(int x)
{
if (x != fa[x])
{
fa[x] = find(fa[x]);
}
return fa[x];
}
void mix(int x, int y)
{
int xx = find(x);
int yy = find(y);
if (h[xx] == h[yy])
{
h[x]++;
fa[yy] = xx;
}
else
{
if (h[xx] < h[yy])
{
fa[xx] = yy;
}
else
{
fa[yy] = xx;
}
}
}
int main()
{
int t;
cin >> t;
while (t--)
{
int ans = 0;
cin >> n >> m;
init();
for (int i = 1; i <= m; i++)
{
int t1, t2;
cin >> t1 >> t2;
mix(t1, t2);
}
for (int i = 1; i <= n; i++)
{
int res = find(i);
if (res == i)
{
ans++;
}
}
cout << ans << endl;
}
return 0;
}
模板就收集在一起吧~
POJ-2524-Ubiquitous Religions
代码部分:
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 5e4 + 10;
int n, m;
int fa[N];
int cnt;
void init()
{
for (int i = 1; i <= n; i++)
{
fa[i] = i;
}
}
int find(int x)
{
if (x != fa[x])
{
fa[x] = find(fa[x]);
}
return fa[x];
}
void mix(int x, int y)
{
int xx = find(x);
int yy = find(y);
if (xx != yy)
{
fa[yy] = xx;
}
}
int main()
{
while (~scanf ("%d%d", &n, &m) && n && m)
{
init();
for (int i = 1; i <= m; i++)
{
int t1, t2;
cin >> t1 >> t2;
mix(t1, t2);
}
int ans = 0;
for (int i = 1; i <= n; i++)
{
if (fa[i] == i)
{
ans++;
}
}
cout << "Case " << ++cnt << ": ";
cout << ans << endl;
}
return 0;
}