zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    Delphi Code Editor 之 几个特性(转)
    如何访问局域网的Access数据库?
    Delphi Live Bindings 初探
    重装Delphi10.2的IDE必要设置
    TClientDataSet数据源设置
    js删除数组里的某个数据
    初识localstorage用法
    Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.
    css实现文本溢出用...显示
    原生js和jquery
  • 原文地址:https://www.cnblogs.com/yxg123123/p/6827576.html
Copyright © 2011-2022 走看看