【bzoj1082】栅栏[SCOI2005]

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

所以两遍排序。

二分答案。

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

要加剪枝:

①如果砍下了这块木材然后这块木材小于第一块木板,那就失去价值,用t来记录。当t>tot-s[now],(tot是记录的所有给的木板长度),那么退出。

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

 

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
 
#define N 60
#define M 1010
 
int n,m;
int tot,mid;
int t;
 
int a[N],b[M],c[N];
int s[M];
 
bool DFS(int now,int d)
{
    if (!now)
        return true;
    if (t>tot-s[mid])
        return false;
    for (int i=d;i<=m;i++)
        if (c[i]>=b[now])
        {
            c[i]-=b[now];
            if (c[i]<b[1])
                t+=c[i];
            if (b[now]==b[now-1])
            {
                if (DFS(now-1,i))
                    return true;
            }
            else
            {
                if (DFS(now-1,1))
                    return true;
            }
            if (c[i]<b[1])
                t-=c[i];
            c[i]+=b[now];
        }
    return false;
}
 
int work(int mid)
{
    for (int i=1;i<=m;i++)
        c[i]=a[i];
    t=0;
    return DFS(mid,1);
}
 
int main()
{
    scanf("%d",&m);
    for (int i=1;i<=m;i++)
        scanf("%d",&a[i]),tot+=a[i];
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&b[i]);
    sort(a+1,a+m+1);
    sort(b+1,b+n+1);
    for (int i=1;i<=n;i++)
        s[i]=s[i-1]+b[i];
    while (s[n]>tot)
        n--;
    int l=0,r=n;
    while (l<r)
    {
        mid=(l+r)>>1;
        if (work(mid+1))
            l=mid+1;
        else
            r=mid;
    }
    printf("%d\n",l);
    return 0;
}

  

posted @ 2016-03-25 20:54  Yangjiyuan  阅读(165)  评论(0编辑  收藏  举报