๐๊ณต๋ถํ ๊ฑฐ List๐
- ํธ๋ฆฌ - 25. ์ํธ ๋ฐฐํ์ ์งํฉ(2)
ํธ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ ์ํธ ๋ฐฐํ์ ์งํฉ์ ํํํ ๊ฒฝ์ฐ ์๊ธฐ๋ ๋ฌธ์ ์
๐ ์ฐ์ฐ์ ์์์ ๋ฐ๋ผ ์์นซ ํธ๋ฆฌ๊ฐ ํ์ชฝ์ผ๋ก ๊ธฐ์ธ์ด์ง ์ ์๋ค.
๐ ๋ ํธ๋ฆฌ๋ฅผ ํฉ์น ๋, ํญ์ ๋์ด๊ฐ ๋ ๋ฎ์ ํธ๋ฆฌ๋ฅผ ๋ ๋์ ํธ๋ฆฌ ๋ฐ์ ์ง์ด๋ฃ์์ผ๋ก์จ ํธ๋ฆฌ์ ๋์ด๊ฐ ๋์์ง๋ ์ํฉ์ ๋ฐฉ์งํ๋ค.
-----(2020.07.25 ๊ณต๋ถ๋ด์ฉ)-----
๋ญํฌ์ ์ํ ํฉ์น๊ธฐ ์ต์ ํ๋ฅผ ์ด์ฉํ ์ํธ ๋ฐฐํ์ ์งํฉ์ ๊ตฌํ
struct OptimizedDisjointSet {
//parent[i] : i์ ๋ถ๋ชจ
//rank[] : ํด๋น ๋
ธ๋๊ฐ ํ ํธ๋ฆฌ์ ๋ฃจํธ์ผ ๊ฒฝ์ฐ ํด๋น ํธ๋ฆฌ์ ๋์ด ์ ์ฅ
vector<int> parent, rank;
OptimizedDisjointSet(int n) : parent(n), rank(n,1) {
for(int i=0; i<n; ++i) parent[i] = i;
}
//u๊ฐ ์ํ ํธ๋ฆฌ์ ๋ฃจํธ ๋ฒํธ ๋ฐํํ๋ ํจ์
int find(int u) {
if(u == parent[u]) return u;
return parent[u] = find(parent[u]);
}
//u๊ฐ ์ํ ํธ๋ฆฌ์ v๊ฐ ์ํ ํธ๋ฆฌ๋ฅผ ํฉ์น๋ ํจ์
void merge(int u, int v) {
//u์ v๊ฐ ์ํ ํธ๋ฆฌ์ ๋ฃจํธ๋ฅผ ๊ฐ๊ฐ ๊ตฌํ๋ค.
u = find(u);
v = find(v);
//u์ v๊ฐ ์ด๋ฏธ ๊ฐ์ ์งํฉ์ ์ํ๋ฉด ํฉ์น๊ธฐ ์ฐ์ฐ ํ์ ์๋ค.
if(u==v) return;
//๋ง์ฝ u๊ฐ ์ํ ํธ๋ฆฌ์ ๋์ด๊ฐ ๋ ๋์ผ๋ฉด, u์ v๋ฅผ ๊ตํํ๋ค.
if(rank[u] > rank[v]) swap(u,v);
//u์ ํธ๋ฆฌ์ ๋์ด๊ฐ v๊ฐ ์ํ ํธ๋ฆฌ์ ๋์ด๋ณด๋ค ๊ฐ๊ฑฐ๋ ๋ฎ์ ์ํ์ด๋ค.
parent[u] = v; //u์ ๋ถ๋ชจ๋ฅผ v๋ก ์ค์ ํ๋ฏ๋ก์จ, u์ ํธ๋ฆฌ๋ฅผ v์ ํธ๋ฆฌ์ ํฉ์น๋ค.
//๋ง์ฝ ๋ ํธ๋ฆฌ์ ๋์ด๊ฐ ๊ฐ๋ค๋ฉด, ํฉ์ณ์ง ๊ฒฐ๊ณผ ํธ๋ฆฌ v์ ๋์ด๋ 1 ์ฆ๊ฐํ ์ํ์ด๋ค.
if(rank[u] == rank[v]) ++rank[v];
}
};
โฑTime-Complexityโฑ
์ด๋ ๊ฒ ์ต์ ํ๋ฅผ ํ๋ฉด find() ์ฐ์ฐ์๊ฐ์ ์ค์ผ ์ ์๋ค.
ํธ๋ฆฌ์ ๋์ด๋ **lg(ํฌํจํ ๋ ธ๋์ ์)**์ ๋น๋กํ์ฌ ํฉ์น๊ธฐ ์ฐ์ฐ๊ณผ ์ฐพ๊ธฐ ์ฐ์ฐ์ ์๊ฐ๋ณต์ก๋๋ **O(lgN)**์ด๋ค.
๐ find(u)
๋ฅผ ํตํด u๊ฐ ์ํ๋ ํธ๋ฆฌ์ ๋ฃจํธ๋ฅผ ์ฐพ์์ ๋ parent[u]
๊ฐ์ ์ด ๋ฃจํธ๋ก ๋ฐ๊พธ๋ฉด ๋ ๋ค์ find(u)
๊ฐ ํธ์ถ๋์์ ๋ ๋ฐ๋ก ๋ฃจํธ๋ฅผ ์ฐพ์ ์ ์๋ค.
int find(int u) {
if(u == parent[u]) return u;
return parent[u] = find(parent[u]);
}
N๊ฐ์ ๋์๊ฐ ๋๋ก๋ง์ผ๋ก ์ฐ๊ฒฐ๋์ด ์๊ณ ๊ฐ ๋๋ก๊ฐ ์ ํํ ๋ ๊ฐ์ ๋์๋ฅผ ์ฐ๊ฒฐํ๋ค. ํญ์ค๋ก ์ธํ ๋๋ก ๋ง๋น ํ ๋๋ก๊ฐ ํ๋์ฉ ๋ณต๊ตฌ๋ ๋๋ง๋ค ์์์ ๋ ๋์ ๊ฐ์ ์๋ก ์๋๊ฐ ๊ฐ๋ฅํ์ง ์์๋ณด๋ ๋ฌธ์ .
โก๏ธkeypointโก๏ธ
- ๊ฐ ๋์๋ฅผ ์์๋ก ํ๊ณ , ์๋๊ฐ ๊ฐ๋ฅํ ๋์๋ค์ ํ๋์ ์งํฉ์ผ๋ก ํํํ๋ค.
- a,b๋ฅผ ์ฐ๊ฒฐํ๋ ๋๋ก๊ฐ ๋ณต๊ตฌ๋์์ ๋, a์ ์ฐ๊ฒฐ๋ ๋์๋ค์ ์งํฉ๊ณผ b์ ์ฐ๊ฒฐ๋ ๋์๋ค์ ์งํฉ์ ํฉ์น๋ค.
+Kruskal์ ์ต์ ์คํจ๋ ํธ๋ฆฌ(Minimum Spanning Tree) ์๊ณ ๋ฆฌ์ฆ
๊ฐ ์งํฉ์ ์ํ ์์์ ์๋ฅผ ์ถ์ ํ๋๋ฐ ๊ตฌ๊ฐ ํธ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
์งํฉ๋ค์ด ํฉ์ณ์ง๋ ๊ณผ์ ์์ ๊ฐ์ฅ ํฐ ์งํฉ์ ํฌ๊ธฐ๊ฐ ์ด๋ป๊ฒ ๋ณํ๋์ง ์ถ์ ํ๊ฑฐ๋ ๊ณผ๋ฐ์๊ฐ ์ถํํ๋ ์์ ์ ์ฐพ๋ ๋ฌธ์ ๋ ๊ตฌ๊ฐํธ๋ฆฌ๋ก ํด๊ฒฐํ ์ ์๋ค.
โก๏ธkeypointโก๏ธ
- ๊ฐ ํธ๋ฆฌ์ ๋ ธ๋์ ๊ฐ์๋ฅผ ๋ด๋ ๋ฐฐ์ด size[]๋ฅผ ์ถ๊ฐํ ๋ค ๋ ์งํฉ์ด ํฉ์ณ์ง ๋๋ง๋ค ๊ฐ์ ๊ฐฑ์ ํด์ค๋ค.
๋ ์ข ๋ฅ์ ํธ์ง๊ธฐ๊ฐ ์๋ค. ๊ฐ ํธ์ง๊ธฐ์ ๋ํด ์ด ๋๊ธ๋ก ์ด ์ฌ๋์ด ์ด๋ค ํธ์ง๊ธฐ๋ฅผ ์ฌ์ฉํ๋์ง ์ ์ถํ์ฌ ํด๋น ํธ์ง๊ธฐ๋ชจ์์ ์ด๋ํ๋ ค๊ณ ํ๋ค. ์ด ๋, ํ ํํฐ์ ์ฐธ์ฌํ๋ ๊ฐ๋ฅํ ์ต๋ ์ธ์์ ๊ณ์ฐํ๋ ๋ฌธ์ .
์ํธ ์ธ์ ๋๊ธ์ ACK a b ํํ๋ก, ์ํธ ๋น๋ฐฉ ๋๊ธ์ DIS a b ํํ๋ก ์ ๋ ฅ์ด ์ฃผ์ด์ง๋ค.
โก๏ธkeypointโก๏ธ
- (์์น 1) ๋ด๊ฐ ์๋๋ฐฉ๊ณผ ๊ฐ์ ํธ์ง๊ธฐ๋ฅผ ์ฌ์ฉํ ๋, ์๋๋ฐฉ๊ณผ ๋ค๋ฅธ ํธ์ง๊ธฐ๋ฅผ ์ฐ๋ ์ฌ๋์ ๋์๋ ๋ค๋ฅธ ํธ์ง๊ธฐ๋ฅผ ์ฌ์ฉํ๋ค.
- (์์น 2) ๋ด๊ฐ ์๋๋ฐฉ๊ณผ ๋ค๋ฅธ ํธ์ง๊ธฐ๋ฅผ ์ฌ์ฉํ ๋, ์๋๋ฐฉ๊ณผ ๋ค๋ฅธ ํธ์ง๊ธฐ๋ฅผ ์ฐ๋ ์ฌ๋์ ๋์ ๊ฐ์ ํธ์ง๊ธฐ๋ฅผ ์ฌ์ฉํ๋ค.
parent[i] = i
: i์ ๋ถ๋ชจ๋
ธ๋. ๋ง์ฝ, i๊ฐ ๋ฃจํธ์ธ ๊ฒฝ์ฐ parent[i] ๋ ์๊ธฐ ์์ ์ด๋ค.
rank[i]
: i๊ฐ ๋ฃจํธ์ธ ๊ฒฝ์ฐ, i๋ฅผ ๋ฃจํธ๋ก ํ๋ ํธ๋ฆฌ์ ๋ญํฌ(= ๋์ด)
enemy[i]
: i๊ฐ ๋ฃจํธ์ธ ๊ฒฝ์ฐ, ํด๋น ์งํฉ๊ณผ ์ ๋๊ด๊ณ์ธ ์งํฉ์ ๋ฃจํธ (์์ผ๋ฉด -1)
size[i]
: i๊ฐ ๋ฃจํธ์ธ ๊ฒฝ์ฐ, ํด๋น ์งํฉ์ ํฌ๊ธฐ(= ์์์ ๊ฐ์)
struct BipartiteUnionFind {
vector<int> parent, rank, enemy, size;
BipartiteUnionFind(int n) : parent(n), rank(n,0), enemy(n,-1), size(n,1) {
for(int i=0; i<n; ++i) parent[i] = i;
}
int find(int u) {
if(parent[u] == u) return u;//๋ฃจํธ์ธ ๊ฒฝ์ฐ, ์์ ๋ฐํ
return parent[u] = find(parent[u]); //๋ฃจํธ ์๋๋ฉด, u์ ๋ถ๋ชจ๋
ธ๋์ ๋ฃจํธ ๋ฐํ
}
int merge(int u, int v) {
if(u==-1 || v==-1) //u์ v๊ฐ ๊ณต์งํฉ์ด๋ผ๋ฉด ๋ ์ค์ ํฐ ๊ฑฐ ๋ฐํ
return max(u,v);
u = find(u); v = find(v);
if(u==v) //u์ v๊ฐ ์ด๋ฏธ ๊ฐ์ ์งํฉ์ ์๋ค๋ฉด, ๋ ์ค ํ๋์ธ u ๋ฐํ(v๋ ๋จ)
return u;
if(rank[u] > rank[v]) //๋ง์ฝ u์ ํธ๋ฆฌ๋์ด๊ฐ ๋ ๋๋ค๋ฉด, ๋ฐ๊ฟ์ค๋ค.(u๊ฐ ๋ ํฌ์ง์๋๋ก)
swap(u,v);
//ํ์ฌ u์ ํธ๋ฆฌ ๋์ด๊ฐ v์ ํธ๋ฆฌ ๋์ด๋ณด๋ค ์๊ฑฐ๋ ๊ฐ์ ์ํ์ด๋ค.
//u์ v์ ํธ๋ฆฌ๋์ด๊ฐ ๊ฐ๋ค๋ฉด, v์ ๋์ด๋ฅผ +1ํด์ค๋ค.(๊ทธ๋ฆผ๊ทธ๋ฆฌ๋ฉด ์ดํด์ฝ๋ค)
if(rank[u] == rank[v]) rank[v]++;
parent[u] = v; //u์ ๋ถ๋ชจ๋
ธ๋๋ฅผ v๋ก ์ค์
size[v] += size[u]; //์์์ ๊ฐ์ ๊ฐฑ์
return v;
}
//u์ v๊ฐ ์๋ก ์ ๋๊ด๊ณ์ผ ๋, ๋ชจ์์ ๋ฌด์ ๋ฐ๋ผ ์ฒ๋ฆฌํด์ฃผ๋ ํจ์
int dis(int u, int v) {
u = find(u); v = find(v); //์ผ๋จ ๋ฃจํธ ์ฐพ์์ฃผ๊ณ
if(u == v) return false; //์ ๋๊ด๊ณ์ธ๋ฐ ๊ฐ์ ์งํฉ์ ์ํด์์ผ๋ฉด ๋ชจ์
int a = merge(u, enemy[v]);//'u'์ 'v์ ์ ๋๊ด๊ณ์ ์๋ ์ฌ๋๋ค'์ ํฉ์น๋ค.
int b = merge(v, enemy[u]);//'v'์ 'u์ ์ ๋๊ด๊ณ์ ์๋ ์ฌ๋๋ค'์ ํฉ์น๋ค.
enemy[a] = b; //์งํฉ b๊ฐ a์ ์ ๋๊ด๊ณ์ ์๋ ์ฌ๋๋ค์ ์งํฉ์ด ๋๋๋ก ์ค์
enemy[b] = a; //์งํฉ a๊ฐ b์ ์ ๋๊ด๊ณ์ ์๋ ์ฌ๋๋ค์ ์งํฉ์ด ๋๋๋ก ์ค์
return true;
}
//u์ v๊ฐ ์๋ก ๊ฐ์ ์งํฉ์ผ ๋(๊ฐ์ ์๋ํฐ ์ฌ์ฉ ์), ๋ชจ์ ์ฒ๋ฆฌํด์ฃผ๋ ํจ์
//๋ชจ์; u์ v๊ฐ ๋ค๋ฅธ ์งํฉ์ ์ํ ๋
//์์น; u๊ฐ v๊ฐ ๊ฐ์ ์งํฉ์ด๋ฏ๋ก u์ ์ ๋๊ด๊ณ ์งํฉ์ v์ ์ ๋๊ด๊ณ ์งํฉ๊ณผ ๊ฐ๋ค.
int ack(int u, int v) {
u = find(u), v = find(v); //๋ฃจํธ ์ฐพ์์ฃผ๊ณ
if(enemy[u] == v) return false; //๋ชจ์
int a = merge(u,v); //a์๋ u์ v๋ฅผ ํฉ์น๊ณ
int b = merge(enemy[u], enemy[v]); //์์น์ ๋ฐ๋ผ, u,v์ ์ ๋๊ด๊ณ ์งํฉ์ ํฉ์น๋ค.
enemy[a] = b; //์งํฉ b๊ฐ a์ ์ ๋๊ด๊ณ์งํฉ์ด ๋๋๋ก ์ค์
//๋ ์งํฉ ๋ค ์ ๋ํ๋ ์งํฉ์ด ์์ผ๋ฉด(= enemy[u]์ enemy[v]๊ฐ ๊ณต์งํฉ์ด๋ฉด) b=-1
if(b != -1) enemy[b] = a;
return true;
}
};
int maxParty(const BipartiteUnionFind& buf) {
int ret = 0;
for(int node=0; node<n; ++node) { //n:์ ์ฒด ํ์์ ์
if(buf.parent[node] == node) {//node๊ฐ ๋ฃจํธ์ด๋ฉด
int enemy = buf.enemy[node];//node์ ์ ๋๊ด๊ณ์ ์๋ ์ฌ๋์ enemy๋ผ๊ณ ํ๊ณ
if(enemy > node) continue; //์ค๋ณต์ ๋ฐฉ์งํ๊ธฐ ์ํ ์ฝ๋
int mySize = buf.size[node];//node์ ์งํฉํฌ๊ธฐ๋ฅผ mySize๋ผ๊ณ ํ๊ณ
//์ ๋๊ด๊ณ์ ์๋ ์ฌ๋์ด ์๋ค๋ฉด ์งํฉํฌ๊ธฐ๋ฅผ 0์ผ๋ก, ์๋๋ผ๋ฉด ๊ทธ ์๋งํผ enemySize ์ค์
int enemySize = (enemy==-1 ? 0 : buf.size[enemy]);
ret += max(mySize, enemySize);//์ต๋์ธ์์ ๊ฐฑ์
}
}
return ret;
}