您的位置:首页 > 其它

bzoj1082[SCOI2005]栅栏

2016-08-15 17:42 253 查看

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

思路:

首先,此题属于最小值最大化问题,果断下二分答案,而此题适用于left no AND right no BUT mid yes 的二分查找。

唔,据网上blogs,背包动归的写法还不如搜索+剪枝,所以此题约等于贪心题目,于是有了:

优化part 1:将店主可提供的木板和farmer John的需要木板进行排序。

那么,暴搜的框架就不再赘述,下面我们看看此题的剪枝。。。

可行性剪枝1:自然是搜完啦farmer John要买的最小mid个的木板后,向二分查找return 1咯。

可行性剪枝2:累计切割后剩下不能再用的木板,计为waste,处理要买的木板的前缀和,计为s[],并且滴,累积商店里所有木板的长度为sum(好吧,tot||total||cnt也行,但是sum s是更和谐的),当s[mid](当前要买的mid个木板总长)+waste>sum时,也就是搜索目标最小值所用最优木板长度比可承受长度还长,那么剪枝。

优化:当枚举的下一个要买到的木板长度和当前搞好的木板长度相同时,继续从当前商店的用过切过的木板i开始解决,否则从1开始。

此题大概就是如此吧,具体的那些难以言表东西交给我的代码解决吧!

二分答案技能get!

//最近get技能read()函数,陷入三目运算符中不能自拔(表示noip不能用啊)。

1592592
ksq20131082Accepted828 kb4 msC++/Edit1287 B2016-08-15 17:16:48
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int l,r,mid,ans=0;
int n,m,c[51],b[51],a[1001],s[1001]={0},sum=0;
int read()
{
int x=0,c=getchar(),f=1;
while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
while(c>47&&c<58)x=x*10+c-48,c=getchar();
return x*f;
}
bool dfs(int last,int waste,int cur)
{
if(!cur)return 1;
if(waste+s[mid]>sum)return 0;
for(int i=last;i<=m;i++)
if(c[i]>=a[cur]){
c[i]-=a[cur];
int tmp=c[i]<a[1]?c[i]:0;
int nxt=a[cur]==a[cur-1]?i:1;
if(dfs(nxt,waste+tmp,cur-1))
return 1;
c[i]+=a[cur];
}
return 0;
}
int main()
{
m=read();
for(int i=1;i<=m;i++)
b[i]=read(),sum+=b[i];
n=read();
for(int i=1;i<=n;i++)
a[i]=read();
sort(a+1,a+1+n);
sort(b+1,b+1+m);
for(int i=1;i<=n;i++)
s[i]=s[i-1]+a[i];
for(;s
>sum;n--);
l=0,r=n;
while(l<=r){
mid=(l+r)>>1;
memcpy(c,b,sizeof(b));
if(dfs(1,0,mid))ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息