[BZOJ1082][SCOI2005]栅栏 二分+搜索减枝

1082: [SCOI2005]栅栏

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2430  Solved: 1034
[Submit][Status][Discuss]

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

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<algorithm>
 7 using namespace std;
 8 int m,n;
 9 int re[101];
10 int a[101],b[1001];
11 int sum,ned;
12 int waste=0;
13 bool dfs(int now,int st) {
14     if(now==0) return 1;
15     if(waste+ned>sum) return 0;
16     for(int i=st;i<=m;i++) {
17         if(a[i]>=b[now])
18         {
19             a[i]-=b[now];
20             if(a[i]<b[1]) waste+=a[i];
21             if(b[now]==b[now-1]) {if(dfs(now-1,i)) return 1;}
22             else if(dfs(now-1,1)) return 1;
23             if(a[i]<b[1]) waste-=a[i];
24             a[i]+=b[now];
25         }
26     }
27     return 0;
28 }
29 bool check(int mid) {
30     ned=0;waste=0;
31     for(int i=1;i<=mid;i++) ned+=b[i];
32     for(int i=1;i<=m;i++) a[i]=re[i];
33     return dfs(mid,1);
34 }
35 int main() {
36     scanf("%d",&m);
37     for(int i=1;i<=m;i++){scanf("%d",&re[i]);sum+=re[i];}
38     scanf("%d",&n);
39     for(int i=1;i<=n;i++) scanf("%d",&b[i]);
40     sort(a+1,a+m+1);
41     sort(b+1,b+n+1);
42     int l=0,r=n;
43     while(l<=r) {
44         int mid=(l+r)>>1;
45         if(check(mid)) l=mid+1;
46         else r=mid-1;
47     }
48     printf("%d",l-1);
49 }
View Code

 

posted @ 2017-10-21 16:43  wls001  阅读(135)  评论(0编辑  收藏  举报