• 1082: [SCOI2005]栅栏


    链接

    思路

      二分+搜索+剪枝。

      首先二分一个答案,表示最多可以切出x块。(一个结论:切出的一定是从较小的前x块。如果一个木材可以满足很多个需要的木材,那么切出最小的,就意味着以后再选时的机会更多。)

      然后暴力搜索前x块分别由哪个木材切出。

      剪枝1:如果所有提供的木材加起来也不能满足需要的木材,直接跳过

      剪枝2:记录一下浪费掉的木材(即一块木材切掉了一些后,剩下的木材中连最小的也切不出了的),如果提供的木材总量-浪费掉<当前所有的木材需要的,直接跳过。

      剪枝3:当前需要的和下一块需要的木材是一样长的,那么不必从第一块开始搜索了,直接从上次搜索到的地方开始。

    代码:

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<iostream>
     4 
     5 using namespace std;
     6 
     7 const int N = 10010;
     8 int n,m,rest,tot;
     9 int a[N],b[N],c[N],sum[N];
    10 
    11 inline int read() {
    12     int x = 0,f = 1;char ch = getchar();
    13     for (; !isdigit(ch); ch=getchar()) if(ch=='-') f=-1;
    14     for (; isdigit(ch); ch=getchar()) x=x*10+ch-'0';
    15     return x * f;
    16 }
    17 bool dfs(int now,int s) { // 当前需要的木材,从给出的木材中第s个开始 
    18     if (!now) return true;
    19     if (rest+sum[now] > tot) return false; // 剪枝2 
    20     for (int i=s; i<=m; ++i) { // 枚举所有给出的木材 
    21         if (c[i] >= b[now]) { // 当前木材可以切出需要的 
    22             c[i] -= b[now]; //-
    23             if (c[i] < b[1]) rest += c[i];
    24             if (b[now]==b[now-1]) {
    25                 if (dfs(now-1,i)) return true;
    26             }
    27             else {if (dfs(now-1,1)) return true;} // 剪枝3 
    28             if (c[i] < b[1]) rest -= c[i];
    29             c[i] += b[now]; // -
    30         }
    31     }
    32     return false;
    33 }
    34 bool check(int x) {
    35     for (int i=1; i<=m; ++i) c[i] = a[i];
    36     rest = 0;
    37     return dfs(x,1);
    38 }
    39 int main() {
    40     m = read();
    41     for (int i=1; i<=m; ++i) a[i] = read(),tot += a[i];
    42     sort(a+1,a+m+1);
    43     n = read();
    44     for (int i=1; i<=n; ++i) b[i] = read();
    45     sort(b+1,b+n+1);
    46     for (int i=1; i<=n; ++i) sum[i] = sum[i-1] + b[i];
    47     
    48     while (sum[n] > tot) n--; // 剪枝1 
    49     int L = 0,R = n,ans; // L有等于0的情况! 
    50     while (L <= R) {
    51         int mid = (L + R) / 2;
    52         if (check(mid)) L = mid + 1,ans = mid;
    53         else R = mid - 1;
    54     }
    55     cout << ans <<'
    ';
    56     return 0;
    57 }
  • 相关阅读:
    CF 319C
    日常---区域赛临近
    poj 3728 The merchant 倍增lca求dp
    zoj 3742 Delivery 好题
    zoj 3717 Balloon 2-sat
    CF 163E. e-Government ac自动机+fail树+树状数组
    CF 335B
    hdu 4739 状压DP
    hdu 4738 桥
    Hibernate中的继承映射
  • 原文地址:https://www.cnblogs.com/mjtcn/p/8960696.html
Copyright © 2020-2023  润新知