BZOJ 1082 【SCOI2005】 栅栏

Description

  农夫约翰打算建立一个栅栏将他的牧场给围起来,因此他需要一些特定规格的木材。于是农夫约翰到木材店购
买木材。可是木材店老板说他这里只剩下少部分大规格的木板了。不过约翰可以购买这些木板,然后切割成他所需
要的规格。而且约翰有一把神奇的锯子,用它来锯木板,不会产生任何损失,也就是说长度为10的木板可以切成长
度为8和2的两个木板。你的任务:给你约翰所需要的木板的规格,还有木材店老板能够给出的木材的规格,求约翰
最多能够得到多少他所需要的木板。

Input

  第一行为整数m(m<= 50)表示木材店老板可以提供多少块木材给约翰。紧跟着m行为老板提供的每一块木板的长
度。接下来一行(即第m+2行)为整数n(n <= 1000),表示约翰需要多少木材。接下来n行表示他所需要的每一块木板
的长度。木材的规格小于32767。(对于店老板提供的和约翰需要的每块木板,你只能使用一次)。

Output

  只有一行,为约翰最多能够得到的符合条件的木板的个数。

 
  嗯……今天的考试题……出题人把数据一加强,卡掉无数贪心……
  看了看这道题,发现分类竟然是基础搜索题……好吧,看来我离noip还有段距离……这种题我做不出……
 
  去网上翻了翻题解,发现都是二分答案,用搜索来检验。这样复杂度虽然还是不对,但显然已经比普通的搜索好到不知道哪里去了。我以前打的二分答案都是用贪心或者dp来检验,今天还是第一次用搜索来检验。新姿势get
  于是,我们每次二分一个答案x,然后显然是尽量选小的木板,于是排序后枚举每个木板去组成什么木材。
  当然,就算这样比朴素搜索要好很多,但是不加剪枝的话显然还是过不了的。于是,仔细思考之后,可以有以下几个优化:
 
  1.当需要的木板不足最小的可以提供的木板时,显然已经没有用了,于是我们可以直接把它丢弃,并记录一下丢弃的木板总长度。当丢弃的木板和前x块木板的长度总和超过所有提供的木板的和时,可以剪掉。
  2.当两个木板长度相同时,那么交换他们组成什么木材对答案没有影响。于是我们就可以强制前面的木板去组成编号大于等于后一个的木材。
 
  加了这两个剪枝就可以过了。当然,由于原题数据水,有些贪心也是可以过的。
  下面贴代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define N 2010
#define INF 2147483647

using namespace std;
typedef long long llg;

int n,m,a[N],b[N],w[N];
int tol,diu,l,r,mid,xu[N];
bool ww;

int getint(){
	int w=0;bool q=0;
	char c=getchar();
	while((c>'9'||c<'0')&&c!='-') c=getchar();
	if(c=='-') c=getchar(),q=1;
	while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
	return q?-w:w;
}

void dfs(int u){
	if(!u) ww=1;
	if(ww || diu+w[mid]>tol) return;
	int l=1;
	if(b[u]==b[u+1] && u!=mid) l=xu[u+1];
	for(int i=l;i<=n;i++)
		if(a[i]>=b[u]){
			xu[u]=i;
			a[i]-=b[u]; if(a[i]<b[1]) diu+=a[i];
			dfs(u-1);
			if(a[i]<b[1]) diu-=a[i]; a[i]+=b[u];
		}
}

int main(){
	File("a");
	n=getint();
	for(int i=1;i<=n;i++) tol+=(a[i]=getint());
	sort(a+1,a+n+1); m=getint();
	for(int i=1;i<=m;i++) b[i]=getint();
	sort(b+1,b+m+1);
	for(int i=1;i<=m;i++) w[i]=w[i-1]+b[i];
	l=0,r=m+1;
	while(l!=r){
		mid=l+r>>1; ww=0;
		dfs(mid);
		if(ww) l=mid+1;
		else r=mid;
	}
	printf("%d",l-1);
}
原文地址:https://www.cnblogs.com/lcf-2000/p/5924094.html