1082栅栏 大视野评测

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

Source

http://www.lydsy.com/JudgeOnline/problem.php?id=1082

以上是题目描述。。。额。。其实我也没看懂。。

一小时后。。。

这道题的基本思路是  二分+搜索(贪心)

注意!!注意!!先排序!!

左端点初始为0,右端点为n;  进行二分。

我们设可以得到mid个 进行验证;

搜索有两个参数(k,deep),k 表示还有几个木块要get(k<n),deep表示现在进行到第几块(deep<m)

然后就是愉快的搜索了!!!

for (int i=deep;i<=m;i++){
    if (a[i]>=b[k]){
        a[i]-=b[k];
        if (a[i]<b[1]) sheng+=a[i];
        if (b[k-1]==b[k]) f=dfs(k-1,i);
        else f=dfs(k-1,1);
        if (a[i]<b[1]) sheng-=a[i];
        a[i]+=b[k];
        if (f) return true;
    }
}

优化:这里sheng表示没用的木材,如果没用的木材+需要的木材>总共的木材,return false;

if (k==0) return true;

不多说,参考一段代码:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 int a[50001]={0},b[50001]={0},s[50001]={0}; 
 6 int n,m;
 7 void qsorta(int left,int right){
 8     int i=left,j=right,mid=a[(left+right)/2];
 9     while (i<=j){
10         while (a[i]<mid) i++;
11         while (a[j]>mid) j--;
12         if (i<=j) {
13             int t=a[i]; a[i]=a[j]; a[j]=t;
14             i++; j--;
15         }
16     }
17     if (i<right) qsorta(i,right);
18     if (left<j) qsorta(left,j);
19 }
20 void qsortb(int left,int right){
21     int i=left,j=right,mid=b[(left+right)/2];
22     while (i<=j){
23         while (b[i]<mid) i++;
24         while (b[j]>mid) j--;
25         if (i<=j) {
26             int t=b[i]; b[i]=b[j]; b[j]=t;
27             i++; j--;
28         }
29     } 
30     if (i<right) qsortb(i,right);
31     if (left<j) qsortb(left,j);
32 }
33 int sheng=0,mid=0,sum=0; //sheng表示没用的木材,sum表示总共木材长度
34 bool dfs(int k,int deep){
35     if (k==0) return true;
36     if (sheng+s[mid]>sum) return false;
37     bool f;
38     for (int i=deep;i<=m;i++){
39         if (a[i]>=b[k]){ //如果当前这一块木材可以截出需要的木材,截下
40             a[i]-=b[k];
41             if (a[i]<b[1]) sheng+=a[i]; //如果这块剩余的木材长度比最小的木材长度小,就扔掉
42             if (b[k-1]==b[k]) f=dfs(k-1,i); //如果需要的木材和前一块相等,继续做
43             else f=dfs(k-1,1);//否则从1开始做
44             if (a[i]<b[1]) sheng-=a[i];//回溯
45             a[i]+=b[k]; 
46             if (f) return true;
47         }
48     }
49     return false;
50 }
51 int main(){ 
52     scanf("%d",&m); for (int i=1;i<=m;i++){ scanf("%d",&a[i]); sum+=a[i]; }
53     scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d",&b[i]); }
54     qsorta(1,m); qsortb(1,n);
55     for (int i=1;i<=n;i++) s[i]=s[i-1]+b[i]; //s[i]表示前i项的和
56     while (s[n]>sum) n--;
57     int l=0,r=n,ans=0;
58     while (l<=r){
59         mid=(l+r)/2;
60         if (dfs(mid,1)) {
61             l=mid+1;
62             ans=mid; 
63         }
64         else r=mid-1;
65     }
66     printf("%d",ans);
67     return 0;
68 } 

代码有点丑,别介意。

原文地址:https://www.cnblogs.com/lztlztlzt/p/6196223.html