[SCOI2005]栅栏(搜索,二分)

[SCOI2005]栅栏(luogu)

Solution

有一个贪心策略——尽量满足较小的需要的木板

于是可以先将需要的木板从小到大排序,二分出最多能满足前多少块木板

有减小二分区间的策略——提供的木块总长度必须 >= 所有要满足的木板的总长度

如何check呢?

考虑暴力思想——搜索,按需要满足的木板顺序搜索

但肯定需要剪枝

剪枝1:提供的木块总长度-当前已舍弃的长度 > = 所有要满足的木板的总长度

剪枝2:及时舍弃不能满足任何木板的 提供的木板

Code

#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int M=51,N=1001;
int a[M],b[N],n,m,tot,ma,t,sum,s[N],fa[M];
bool dfs(int k,int x,int mid)
{
    if(k<=0) return 1;
    if(sum-t<s[mid]) return 0;
    for(int i=x;i<=m;i++)
        if(fa[i]>=b[k])
        {
            fa[i]-=b[k];
            if(fa[i]<b[1]) t+=fa[i];
            if(b[k]==b[k-1])
            {
                if(dfs(k-1,i,mid)) return 1;
            }
            else if(dfs(k-1,1,mid)) return 1;
            if(fa[i]<b[1]) t-=fa[i];
            fa[i]+=b[k];
        }
    return 0;
}
int main()
{
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
        scanf("%d",&a[i]),ma=max(ma,a[i]);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&b[++tot]);
        if(b[tot]>ma) tot--;
    }
    n=tot,tot=0;
    sort(b+1,b+1+n);
    for(int i=1;i<=m;i++)
        if(a[i]>=b[1]) a[++tot]=a[i];
    m=tot;
    sort(a+1,a+1+m);
    
    for(int i=1;i<=m;i++) sum+=a[i];
    for(int i=1;i<=n;i++) s[i]=s[i-1]+b[i];
    while(sum<s[n]) n--;
    int l=0,r=n;
    while(l<r)
    {
        t=0;
        for(int i=1;i<=m;i++) fa[i]=a[i];
        int mid=(l+r+1)>>1;
        if(dfs(mid,1,mid)) l=mid;
        else r=mid-1;
    }
    printf("%d\n",l);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hsez-cyx/p/12446614.html
今日推荐