POJ 1944 Fiber Communications (枚举 + 并查集 OR 线段树)
生活随笔
收集整理的這篇文章主要介紹了
POJ 1944 Fiber Communications (枚举 + 并查集 OR 线段树)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
題意
在一個(gè)有N(1 ≤ N ≤ 1,000)個(gè)點(diǎn)環(huán)形圖上有P(1 ≤ P ≤ 10,000)對(duì)點(diǎn)需要連接。連接只能連接環(huán)上相鄰的點(diǎn)。問(wèn)至少需要連接幾條邊。思路
突破點(diǎn)在于最后的結(jié)果一定不是一個(gè)環(huán)!所以我們枚舉斷邊,則對(duì)于P個(gè)連接要求都只有唯一的方法:如果一個(gè)pair的兩個(gè)端點(diǎn)在斷點(diǎn)兩側(cè),就分成[0,left],[right,N];否則就是[left, right]。這里區(qū)間以0開(kāi)頭是要考慮left=1、right=N的情況,至少得有個(gè)邊([0, 1])表示N連向1的情況不是么。 處理一個(gè)區(qū)間內(nèi)相連情況通常可以用線段樹(shù)。不過(guò)我在這里用了下并查集,也挺有意思的:每個(gè)并查集的父節(jié)點(diǎn)是它連接著的最右端的節(jié)點(diǎn),并且維護(hù)一個(gè)數(shù)量集。然后連接[x, y]的時(shí)候直接找x的父節(jié)點(diǎn)(最右點(diǎn)),再挨個(gè)向右縮點(diǎn)直到y(tǒng)即可。代碼
? [cpp] #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <string> #include <cstring> #include <vector> #include <set> #include <stack> #include <queue> #define MID(x,y) ((x+y)/2) #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i, begin, end) for (int i = begin; i <= end; i ++) using namespace std; struct P{ int a, b; }p[10005]; const int MAXN = 1005; struct Disjoint_Sets{ struct Sets{ int father, num; }S[MAXN]; void Init(int n){ for (int i = 0; i <= n; i ++){ S[i].father = i; S[i].num = 1; } } int Father(int x){ if (S[x].father == x){ return x; } else{ S[x].father = Father(S[x].father); //Path compression return S[x].father; } } void Union(int x, int y){ int fx = Father(x), fy = Father(y); S[fy].num += S[fx].num; S[fx].father = fy; } }DS; void uni(int x, int y){ int xx = DS.Father(x); while(DS.Father(xx) != DS.Father(y)){ DS.Union(xx, xx+1); xx = DS.Father(xx); } } int main(){ //freopen("test.in", "r", stdin); //freopen("test.out", "w", stdout); int n, m; scanf("%d %d", &n, &m); for (int i = 0; i < m; i ++){ scanf("%d %d", &p[i].a, &p[i].b); if (p[i].b < p[i].a) swap(p[i].b, p[i].a); } int res = 0x3fffffff; for (int l = 1; l <= n; l ++){ DS.Init(n); for (int i = 0; i < m; i ++){ if (p[i].a <= l && p[i].b >= (l+1)%n){ uni(0, p[i].a); uni(p[i].b, n); } else uni(p[i].a, p[i].b); } int sum = 0; bool vis[1005] = {0}; for (int i = 1; i <= n; i ++){ if (!vis[DS.Father(i)] && DS.S[DS.Father(i)].num > 1){ sum += DS.S[DS.Father(i)].num - 1; vis[DS.Father(i)] = 1; } } res = min(res, sum); } printf("%d\n", res); return 0; } [/cpp]轉(zhuǎn)載于:https://www.cnblogs.com/AbandonZHANG/p/4114139.html
總結(jié)
以上是生活随笔為你收集整理的POJ 1944 Fiber Communications (枚举 + 并查集 OR 线段树)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 试管婴儿成功率和什么有关?
- 下一篇: hdu 4747 mex 线段树+思维