bzoj1082 [SCOI2005]栅栏
Posted wfj_2048
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1082 [SCOI2005]栅栏相关的知识,希望对你有一定的参考价值。
Description
农夫约翰打算建立一个栅栏将他的牧场给围起来,因此他需要一些特定规格的木材。于是农夫约翰到木材店购买木材。可是木材店老板说他这里只剩下少部分大规格的木板了。不过约翰可以购买这些木板,然后切割成他所需要的规格。而且约翰有一把神奇的锯子,用它来锯木板,不会产生任何损失,也就是说长度为10的木板可以切成长度为8和2的两个木板。你的任务:给你约翰所需要的木板的规格,还有木材店老板能够给出的木材的规格,求约翰最多能够得到多少他所需要的木板。
Input
第一行为整数m(m<= 50)表示木材店老板可以提供多少块木材给约翰。紧跟着m行为老板提供的每一块木板的长度。接下来一行(即第m+2行)为整数n(n <= 1000),表示约翰需要多少木材。接下来n行表示他所需要的每一块木板的长度。木材的规格小于32767。(对于店老板提供的和约翰需要的每块木板,你只能使用一次)。
Output
只有一行,为约翰最多能够得到的符合条件的木板的个数。
Sample Input
30
40
50
25
10
15
16
17
18
19
20
21
25
24
30
Sample Output
HINT
25切出 21 30切出 20 40切出 19、18 50切出 15、16、17
正解:二分答案+搜索。
这道题,如果知道标签就不难了。。
首先二分答案,二分出$mid$后,我们肯定是拿最小的$mid$个木块看能不能凑出来。
然后我们考虑搜索,先搜大木块后搜小木块,这样状态会少一些。
然后加一些剪枝,首先如果一个木板被砍了一截以后,比最小的木块还小了,那么它肯定就没用了,我们可以把它剩下的长度记到浪费的木板中。
每次判断如果浪费的木板+需要的总长度大于能提供的总长度,就可以退出了。
然后如果两个木块相同,我们可以记一个$last$,表示上一个是从哪里转移来的,这样从$last$开始再往后选木板,就可以不重复搜索了。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 6 using namespace std; 7 8 int a[1010],b[1010],sum[1010],n,m,l,r,tot,ans,waste; 9 10 il int gi(){ 11 RG int x=0,q=1; RG char ch=getchar(); 12 while ((ch<‘0‘ || ch>‘9‘) && ch!=‘-‘) ch=getchar(); 13 if (ch==‘-‘) q=-1,ch=getchar(); 14 while (ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-48,ch=getchar(); 15 return q*x; 16 } 17 18 il int dfs(RG int x,RG int lim,RG int last){ 19 if (!x) return 1; if (waste+sum[lim]>tot) return 0; 20 for (RG int i=last;i<=n;++i){ 21 if (a[i]<b[x]) continue; a[i]-=b[x]; 22 if (a[i]<b[1]) waste+=a[i]; 23 if (b[x-1]==b[x]){ 24 if (dfs(x-1,lim,i)){ 25 if (a[i]<b[1]) waste-=a[i]; 26 a[i]+=b[x]; return 1; 27 } 28 } else if (dfs(x-1,lim,1)){ 29 if (a[i]<b[1]) waste-=a[i]; 30 a[i]+=b[x]; return 1; 31 } 32 if (a[i]<b[1]) waste-=a[i]; a[i]+=b[x]; 33 } 34 return 0; 35 } 36 37 il int check(RG int key){ return dfs(key,key,1); } 38 39 int main(){ 40 #ifndef ONLINE_JUDGE 41 freopen("fence.in","r",stdin); 42 freopen("fence.out","w",stdout); 43 #endif 44 m=gi(); for (RG int i=1;i<=m;++i) a[i]=gi(),tot+=a[i]; 45 n=gi(); for (RG int i=1;i<=n;++i) b[i]=gi(); 46 sort(a+1,a+m+1),sort(b+1,b+n+1),r=n; 47 for (RG int i=1;i<=n;++i){ 48 sum[i]=sum[i-1]+b[i]; if (a[i]>b[i]) ++l; 49 if (sum[i]>tot) r=min(r,i-1); 50 } 51 while (l<=r){ 52 RG int mid=(l+r)>>1; 53 if (check(mid)) ans=mid,l=mid+1; else r=mid-1; 54 } 55 cout<<ans; return 0; 56 }
以上是关于bzoj1082 [SCOI2005]栅栏的主要内容,如果未能解决你的问题,请参考以下文章