您的位置:首页 > 其它

BZOJ1082: [SCOI2005]栅栏

2015-12-09 19:07 134 查看
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1082

二分+dfs判定。

显然我们取的肯定是前ans块木板。然后砍的木材也应该是从小到大砍(如果小的木材可以满足条件我一定不会去动大的木材嘛。

所以两遍排序。二分答案。

然后对于要取的每块木板,我们搜索它是在第x块木板上砍下来的。。

要加剪枝:①如果砍下了这块木材然后这块木材小于第一块木板,那就失去价值,开个rest来记录。当rest+sum[dep]>s那么退出。

②如果b[dep]==b[dep-1]那么从当前点开始枚举就可以了,因为前面小的点都被我跳掉了。。

感觉还是很有启发性的,详情看代码吧TAT

#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define down(i,l,r) for (int i=l;i>=r;i--)
#define clr(x,y) memset(x,y,sizeof(x))
#define maxn 2005
#define ll long long
using namespace std;
int a[maxn],b[maxn],c[maxn],sum[maxn],s,n,m,l,r,ans,rest;
int read(){
int x=0,f=1; char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
bool dfs(int dep,int last){
if (dep<=0) return 1;
if (rest+sum[dep]>s) return 0;
rep(i,last,n) if (c[i]>=b[dep]){
c[i]-=b[dep];
if (c[i]<b[1]) rest+=c[i];
if (b[dep]==b[dep-1]) {if (dfs(dep-1,i)) return 1;}
else {if (dfs(dep-1,1)) return 1;}
if (c[i]<b[1]) rest-=c[i];
c[i]+=b[dep];
}
return 0;
}
bool jud(int mid){
rep(i,1,n) c[i]=a[i];
rest=0;
return dfs(mid,1);
}
int main(){
//    freopen("in.txt","r",stdin);
n=read(); rep(i,1,n) a[i]=read(),s+=a[i];
m=read(); rep(i,1,m) b[i]=read();
sort(a+1,a+1+n);
sort(b+1,b+1+m);
rep(i,1,m) sum[i]=sum[i-1]+b[i];
while (sum[m]>s) m--;
l=0; r=m;
while (l<r){
int mid=(l+r)/2;
if (jud(mid+1)) l=mid+1;
else r=mid;
}
printf("%d\n",l);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: