首页 > 代码库 > BZOJ1082 [SCOI2005]栅栏

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]栅栏