zoukankan      html  css  js  c++  java
  • BZOJ1082 [SCOI2005]栅栏

    Description

      农夫约翰打算建立一个栅栏将他的牧场给围起来,因此他需要一些特定规格的木材。于是农夫约翰到木材店购
    买木材。可是木材店老板说他这里只剩下少部分大规格的木板了。不过约翰可以购买这些木板,然后切割成他所需
    要的规格。而且约翰有一把神奇的锯子,用它来锯木板,不会产生任何损失,也就是说长度为10的木板可以切成长
    度为8和2的两个木板。你的任务:给你约翰所需要的木板的规格,还有木材店老板能够给出的木材的规格,求约翰
    最多能够得到多少他所需要的木板。

    Input

      第一行为整数m(m<= 50)表示木材店老板可以提供多少块木材给约翰。紧跟着m行为老板提供的每一块木板的长
    度。接下来一行(即第m+2行)为整数n(n <= 1000),表示约翰需要多少木材。接下来n行表示他所需要的每一块木板
    的长度。木材的规格小于32767。(对于店老板提供的和约翰需要的每块木板,你只能使用一次)。

    Output

      只有一行,为约翰最多能够得到的符合条件的木板的个数。

    Sample Input

    4
    30
    40
    50
    25
    10
    15
    16
    17
    18
    19
    20
    21
    25
    24
    30

    Sample Output

    7

    HINT

    25切出 21 30切出 20 40切出 19、18 50切出 15、16、17

    正解:二分答案+搜索

    解题报告:

      今天考试T2。

      考场上面写的是二分+贪心,然而我自己也拍出错来了。但是因为姿势比较正确,拿到了70分。可以证明这道题没有办法贪心,只能选择搜索。当然,即便是搜索,也许要用到二分。然而m<=1000的数据范围简直让人绝望啊...我们只能想办法剪枝,有一些剪枝很清楚:排序,去掉无用的。这题还有一些剪枝:如果某个盆子已经装不下任何一个(就是最小的都装不下了)可以记录一下浪费了多少空间,然后加起来,如果超过了总容量与当前二分值的差,那么一定无法放完。还有就是如果下一个星星的体积与当前相同(即完全相同),那么可以发现没必要从1开始重新扫一遍,因为当前用到i就说明之前的已经放不下了,所以可以记录一下循环开始的位置,从而减少迭代。这样的话就可以过掉USACO还有SCOI的所有数据了。

     

     

     1 //It is made by jump~
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 #include <algorithm>
     8 #include <ctime>
     9 #include <vector>
    10 #include <queue>
    11 #include <map>
    12 #include <set>
    13 using namespace std;
    14 typedef long long LL;
    15 const int inf = (1<<30);
    16 const int MAXN = 60;
    17 const int MAXM = 1030;
    18 int n,m,cnt,l,r;
    19 int a[MAXN],star[MAXM],c[MAXM],sum[MAXM];
    20 int ans,rest,tot,now;
    21 
    22 inline int getint()
    23 {
    24     int w=0,q=0; char c=getchar();
    25     while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); 
    26     while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w;
    27 }
    28 
    29 inline bool dfs(int x,int from){
    30     if(x==0) return true;
    31     if(now>rest) return false;
    32     for(int i=from;i<=n;i++) {
    33     if(a[i]<star[x]) continue;
    34     a[i]-=star[x];
    35     if(a[i]<star[1]) now+=a[i];//i没有任何作用了,加入剩余的中,进入剪枝
    36     if(star[x]==star[x-1]) { if(dfs(x-1,i))return true;}//直接从这一位开始,因为已经扫描到i说明之前的已经无用了
    37     else if(dfs(x-1,1)) return true;
    38     if(a[i]<star[1]) now-=a[i]; 
    39     a[i]+=star[x];
    40     }
    41     return false;
    42 }
    43  
    44 inline void work(){
    45     n=getint(); for(int i=1;i<=n;i++) c[i]=a[i]=getint(),tot+=a[i];
    46     m=getint(); for(int i=1;i<=m;i++) star[i]=getint(); 
    47     sort(a+1,a+n+1); sort(c+1,c+n+1); sort(star+1,star+m+1);    
    48     for(int i=1;i<=m;i++) sum[i]=sum[i-1]+star[i];
    49     int mid; l=0;  while(sum[m]>tot) m--;//去掉没有意义的
    50     r=m;
    51     while(l<=r) {
    52     mid=(l+r)/2; now=0; rest=tot-sum[mid];//剩余的
    53     if(dfs(mid,1)) l=mid+1,ans=mid;
    54     else r=mid-1;
    55     for(int i=1;i<=n;i++) a[i]=c[i];
    56     }
    57     printf("%d",ans);
    58 }
    59 
    60 int main()
    61 {
    62     work();
    63     return 0;
    64 }

     

     

  • 相关阅读:
    位运算
    LeetCode(230):二叉树中的第K小元素
    LeetCode(69):二分法求平方根
    TCP如何保证传输可靠性
    2种方法(递归+BFS)求二叉树的最小/最大深度
    自动生成Mapper文件(基于Mybatis Maven插件)
    Git的使用
    Java关键字及其作用详解
    Vagrant安装Centos/7
    java servlet 几种页面跳转的方法及传值
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5924770.html
Copyright © 2011-2022 走看看