BZOJ1082 [SCOI2005]栅栏

Posted ljh2000

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }

 

 

 

以上是关于BZOJ1082 [SCOI2005]栅栏的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1082 SCOI2005—栅栏

BZOJ1082: [SCOI2005]栅栏

bzoj1082: [SCOI2005]栅栏(二分答案搜索判断)

BZOJ1082 [SCOI2005]栅栏

bzoj1082 [SCOI2005]栅栏

BZOJ1082: [SCOI2005]栅栏 题解