51nod 1307 绳子与重物 二分+dfs / 并查集
題目鏈接:
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1307
題意:
題解:
方法一:
因為所有繩子最終組成了1棵樹,所以我們可以通過一次DFS,來檢測是否有某根繩子下面綁了超過他所能負荷的重量。
具體方法:對每個節點,計算其子樹的重量和(包含自身的重量),如果大于能承受的最大重量,則繩子會斷,否則不會斷。
一次DFS時間復雜度是O(n)的。
既然一次判斷的復雜度是O(n)的,并且當繩子第一次斷掉后,繼續放重物,不會改變繩子斷掉的狀態(畢竟重物的重量都是正數,沒有負數),那么我們可以用二分來做。
二分來求第一次斷掉的點,由于二分的復雜度是log(n),一次DFS判斷的復雜度是O(n),所以整個算法的復雜度是nlog(n)。
二分經常被用來求解一些具有單調性的問題,這里的單調性就是斷掉以后,不會再次變成不斷的。
方法二:
我們在DFS的過程中,使用并查集,將子樹節點的Root指向當前節點,同時計算子樹的總重量。
假如當前節點的承重不足,那么繩子會斷掉。所以我們需要去掉一些節點,來保證繩子不斷。根據題目要求,我們按照子樹節點的編號從高到低,逐個去掉這些重物,直到繩子不斷為止。
那么問題來了,并查集這個結構并不能解決按照編號從高到低去掉子樹的問題,如果自己維護其他的數據結構(比如堆),恐怕復雜度還要多一個Log。
所以我們跳出按照編號從高到低去掉子樹的思路,不如直接從編號N - 1到0去掉子樹,直到當前的繩子不斷為止。 因為編號小的斷了,后面再加的繩子也沒有用了,已經有繩子斷了就結束了。
代碼:
二分:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define MS(a) memset(a,0,sizeof(a)) 5 #define MP make_pair 6 #define PB push_back 7 const int INF = 0x3f3f3f3f; 8 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; 9 inline ll read(){ 10 ll x=0,f=1;char ch=getchar(); 11 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 13 return x*f; 14 } 15 // 16 const int maxn = 1e5+10; 17 18 struct node{ 19 int c,w,f; 20 }e[maxn]; 21 22 vector<int> g[maxn]; 23 24 bool book; 25 26 ll dfs(int u,int k){ 27 ll sum = e[u].w; 28 if(u > k) return 0; 29 for(auto v : g[u]) 30 sum += dfs(v,k); 31 if(sum > e[u].c && u) book = false; 32 return sum; 33 } 34 35 int main(){ 36 int n=read(); 37 for(int i=1; i<=n; i++){ 38 e[i].c=read(); e[i].w=read(); e[i].f=read(); e[i].f++; 39 g[e[i].f].push_back(i); 40 } 41 42 int l=0,r=n,ans = 0; 43 while(l<=r){ 44 int mid = (l+r)/2; 45 book = true; 46 dfs(0,mid); 47 if(book) ans=mid,l=mid+1; 48 else r=mid-1; 49 } 50 51 cout << ans << endl; 52 53 return 0; 54 }?
并查集:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define MS(a) memset(a,0,sizeof(a)) 5 #define MP make_pair 6 #define PB push_back 7 const int INF = 0x3f3f3f3f; 8 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; 9 inline ll read(){ 10 ll x=0,f=1;char ch=getchar(); 11 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 13 return x*f; 14 } 15 // 16 const int maxn = 1e5+10; 17 18 struct node{ 19 ll c,w,f; 20 }e[maxn]; 21 22 vector<int> g[maxn]; 23 int fa[maxn]; 24 ll ww[maxn]; 25 int k; 26 27 int find(int x){ 28 return fa[x]==x ? x : fa[x]=find(fa[x]); 29 } 30 31 void update(int u){ 32 for(auto v : g[u]){ 33 e[u].w += e[v].w; 34 fa[v] = u; 35 } 36 37 while(e[u].w > e[u].c){ 38 e[find(k)].w -= ww[k]; 39 k--; 40 } 41 } 42 43 int main(){ 44 int n=read(); 45 for(int i=1; i<=n; i++){ 46 e[i].c=read(); e[i].w=read(); e[i].f=read(); e[i].f++; 47 g[e[i].f].push_back(i); ww[i] = e[i].w; 48 fa[i] = i; 49 } 50 51 k = n; 52 for(int i=n; i>0; i--) 53 update(i); 54 55 cout << k << endl; 56 57 return 0; 58 }?
轉載于:https://www.cnblogs.com/yxg123123/p/6827576.html
總結
以上是生活随笔為你收集整理的51nod 1307 绳子与重物 二分+dfs / 并查集的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux下socket连接下的心跳机制
- 下一篇: 视频处理器