bzoj1082[SCOI2005]栅栏

    xiaoxiao2025-11-06  6

    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[n]>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; }

    转载请注明原文地址: https://ju.6miu.com/read-1303907.html
    最新回复(0)