BZOJ1082: [SCOI2005]栅栏
Posted ACist
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ1082: [SCOI2005]栅栏相关的知识,希望对你有一定的参考价值。
1082: [SCOI2005]栅栏
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1906 Solved: 816
[Submit][Status][Discuss]
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
Source
题解:神奇的DFS+剪枝
二分答案:我们先排序所有需要裁出来的木头,再二分答案!
DFS:我们考虑每块木头由谁裁剪出来 时间复杂度:n^m
剪枝:1.当出现答案时,不再回溯!
2.当剩下的木材<需要裁的木材时!
3.当当前木材大小等于前一个木材大小时,从它的最小匹配开始!【这个剪枝是最关键的】
总结:反正这样就A了,而且跑的飞快,我一直认为剪枝这种东西过于玄幻,
导致我这种弱菜根本不会分析时间复杂度,果然暴力出奇迹这句话是没错的!
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<cmath> #define ll long long #define ld long double #define N 1005 using namespace std; int n,m,sa,mid,ans; int a[N],b[N],sb[N],bl[N]; bool bool_flag; int read() { int x=0,f=1; char ch; while (ch=getchar(),ch<‘0‘||ch>‘9‘) if (ch==‘-‘) f=-1; while (x=x*10+ch-‘0‘,ch=getchar(),ch>=‘0‘&&ch<=‘9‘); return x*f; } void dfs(int A,int B,int w) { if (B==0) {bool_flag=1; return;} while (A<=n && a[A]<b[1]) w+=a[A],A++; if (bool_flag || w+sb[mid]>sa || A>n) return; int t=A,t1=A,t2=B,t3=w; if (b[B]==b[B+1] && B!=mid) t=bl[B+1]; for (int i=t; i<=n; i++) { if (a[i]>=b[B]){ bl[B]=i; a[i]-=b[B]; B--; dfs(A,B,w); A=t1; B=t2; w=t3; a[i]+=b[B]; } } } int main() { n=read(); for (int i=1; i<=n; i++) a[i]=read(); m=read(); for (int i=1; i<=m; i++) b[i]=read(); sort(a+1,a+n+1); sort(b+1,b+m+1); while (b[m]>a[n]) m--; int tot=0; for (int i=1; i<=n; i++) if (a[i]>b[1]) a[++tot]=a[i]; n=tot; for (int i=1; i<=n; i++) sa+=a[i]; sb[0]=0; for (int i=1; i<=m; i++) sb[i]=sb[i-1]+b[i]; int l=1,r=m; // cout<<" "<<n<<" "<<m<<endl; while (l<=r) { mid=(l+r)>>1; bool_flag=0; dfs(1,mid,0); if (bool_flag) ans=mid,l=mid+1; else r=mid-1; } printf("%d\n",ans); return 0; } /* 4 30 40 50 25 10 20 20 20 20 20 20 20 20 20 20 */
以上是关于BZOJ1082: [SCOI2005]栅栏的主要内容,如果未能解决你的问题,请参考以下文章