acm常用技巧四 超大背包问题

一.超大背包问题

pair<LL,LL> ps[1<<(MXN/2)];
void Fun(){
    int n2=n/2;
    for(int i=0;i<1<<n2;++i){
        LL sw=0,sv=0;
        for(int j=0;j<n2;++j)
            if(i>>j&1){
                sw+=w[j];
                sv+=v[j];
            }
        ps[i]=make_pair(sw,sv);
    }
    sort(ps,ps+(1<<n2));
    int m=1;
    for(int i=1;i<1<<n2;++i)
        if(ps[m-1].second<ps[i].second)
            ps[m++]=ps[i];
    LL res=0;
    for(int i=0;i<1<<(n-n2);++i){
        LL sw=0,sv=0;
        for(int j=0;j<n-n2;++j){
            if(i>>j&1){
                sw+=w[n2+j];
                sv+=v[n2+j];
            }
        }
        if(sw<=W){
            LL tv=(lower_bound(ps,ps+m,make_pair(W-sw,INF))-1)->second;
            res=max(res,sv+tv);
        }
    }
    printf("%lld\n",res);
}

二.坐标离散化

int compress(int x1[],int x2[],int w){
    vector<int> xs;
    for(int i=0;i<N;++i)
        for(int d=-1;d<=1;++d){
            int tx1=x1[i]+d,tx2=x2[i]+d;
            if(1<=tx1&&tx1<=W) xs.push_back(tx1);
            if(1<=tx2&&tx2<=W) xs.push_back(tx2);
        }

    sort(xs.begin(),xs.end());
    xs.erase(unique(xs.begin(),xs.end()),xs.end());
    for(int i=0;i<N;++i){
        x1[i]=find(xs.begin(),xs.end(),x1[i])-xs.begin();
        x2[i]=find(xs.begin(),xs.end(),x2[i])-xs.begin();
    }
    return xs.size();
}
void Fun(){
    W=compress(X1,X2,W);
    H=compress(Y1,Y2,H);

    memset(fld,0,sizeof(fld));
    for(int i=0;i<N;++i)
        for(int y=Y1[i];y<=Y2[i];++y)
            for(int x=X1[i];x<=X2[i];++x)
                fld[y][x]=1;
    int ans=0;
    for(int y=0;y<H;++y)
        for(int x=0;x<W;++x){
            if(fld[y][x]) continue;
            ans++;
            queue<pair<int,int> > que;
            que.push(make_pair(x,y));
            while(!que.empty()){
                int sx=que.front().first,sy=que.front().second;
                que.pop();
                for(int i=0;i<4;++i){
                    int tx=sx+dx[i],ty=sy+dy[i];
                    if(tx<0||W<=tx||ty<0||H<=ty) continue;
                    if(fld[ty][tx]) continue;
                    que.push(make_pair(tx,ty));
                    fld[ty][tx]=true;
                }
            }
        }
    printf("%d\n",ans);
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值