普通背包水题集合 2019/6/17

最近没写DP,回来写几道水题。

P1064 金明的预算方案

有连带条件的背包问题,对于每个非叶子节点,他的每一个儿子的组合方式都可以枚举跑,类似于树形DP但简单的多

对于每个父亲,选择1号儿子,选择2号儿子,12儿子都选,都不选,或者是自己都不选(写转移时体现在MAX)

注意下标越界和末状态,以及代码构造技巧。

#include<bits/stdc++.h>
using namespace std;
int n,m,mw[65],mc[65],aw[65][5] ,ac[65][5],f[50000];

int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int v,p,q;
        cin>>v>>p>>q;
        if(!q){
            mw[i] = v;
            mc[i] = v * p;
        }
        else {
            aw[q][0] ++;
            aw[q][aw[q][0]] = v;
            ac[q][aw[q][0]] = v * p;
        }
    }
    for(int i=1;i<=m;i++){
        for(int j=n;mw[i] != 0 && j >= mw[i];j--){//倒序 01背包 
            f[j]  = max(f[j] , f[j - mw[i]] + mc[i]);
            if(j >= mw[i] + aw[i][1])
                f[j] = max(f[j],f[j-mw[i]-aw[i][1]] + mc[i] + ac[i][1]);
            if(j >= mw[i] + aw[i][2])
                f[j] = max(f[j],f[j-mw[i]-aw[i][2]] + mc[i] + ac[i][2]);
            if(j >= mw[i] + aw[i][1] + aw[i][2])
                f[j] = max(f[j],f[j-mw[i]-aw[i][1]-aw[i][2]] + mc[i] + ac[i][1] + ac[i][2]);
        }
    }
    cout<<f[n]<<endl;
    return 0;
}

P1049 装箱问题

我傻了,刚看到时还以为是什么恰好背包,谢罪谢罪.......

#include<bits/stdc++.h>

using namespace std;

const int MAXN = 35,MAXM = 20010;
int n,a[MAXN],f[MAXM],m;

int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>a[i];
    }
    for(int i = 1;i<=m;i++){
        int nv = a[i];
        for(int j = n;j>=nv;j--){
            f[j] = max(f[j] , f[j-nv] + nv);
        }
    }
    cout<<n-f[n]<<endl;
    return 0;
}

P1455 搭配购买

我也想买云朵...(你写的题怎么都这么水啊)

并查集,合并物品,背包,perfect。

等等让我去看看并查集怎么写(打死自己)

#include<bits/stdc++.h>

using namespace std; 

const int MAXN = 10100;//第一次数组还开小了
struct RAINBOW{
    int cos,val;
}a[MAXN],b[MAXN];

int n,m,v,fa[MAXN],f[MAXN];
int find(int x){
    return (fa[x] == x) ? x : fa[x] = find(fa[x]);
}

int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m>>v;
    for(int i=1;i<=n;i++){
        cin>>a[i].cos>>a[i].val;
    }
    for(int i=1;i<=n;i++) fa[i] = i;
    for(int i=1;i<=m;i++){
        int x,y;
        cin>>x>>y;
//蒟蒻自裁 这里并查集写错导致WA了一次
if(find(x) != find(y)) fa[find(x)] = y;//是合并他们的父亲 不是儿子简单连边 } for(int i=1;i<=n;i++){ int now = find(i); b[now].cos += a[i].cos; b[now].val += a[i].val; } for(int i=1;i<=n;i++){ if(b[i].val){ for(int j=v;j>=b[i].cos;j--){ f[j] = max(f[j],f[j-b[i].cos] + b[i].val); } } } cout<<f[v]<<endl; return 0; }

P1910 L国的战斗之间谍

第一眼:什么东西?

然后仔细看觉得应该就是个强制压掉一位的01背包

一看数据范围1000*1000 空间应该是对的吧

然后就A了 注意循环时的顺序和下标爆炸问题

但是蒟蒻跑了4000ms被爆踩

#include<bits/stdc++.h>

using namespace std;

const int MAXN = 105,MAXM = 1010;
struct PEOPLE{
    int val,cov,cos;
}a[MAXN];

int n,c,v;
int f[MAXM][MAXM];

int main(){
    ios::sync_with_stdio(false);
    cin>>n>>c>>v;
    for(int i=1;i<=n;i++){
        cin>>a[i].val>>a[i].cov>>a[i].cos;
    }
    for(int i=1;i<=n;i++){
        for(int k=c;k>=a[i].cov;k--){
            for(int l=v;l>=a[i].cos;l--){
                f[k][l] = max(f[k][l],f[k-a[i].cov][l-a[i].cos] + a[i].val);
            }
        }
    }
    cout<<f[c][v]<<endl;
    return 0;
}

P1510 精卫填海

水题,直接跑压掉第几个石头的01背包

最后遍历最后一行统计答案

#include<bits/stdc++.h>

using namespace std ;

const int MAXN = 10010;
int v,n,c;
struct STONE{
    int v,cos;
}a[MAXN];

int f[MAXN];//tag->cos f[]->v

int main(){
    ios::sync_with_stdio(false);
    cin>>v>>n>>c;
    for(int i=1;i<=n;i++) {
        cin>>a[i].v>>a[i].cos;
    }
    for(int i=1;i<=n;i++) {
        for(int j=c;j>=a[i].cos;j--){
            f[j] = max(f[j],f[j-a[i].cos] + a[i].v);
        }
    }
    int ans = -1;
    for(int i=1;i<=c;i++){
        if(f[i] >= v) ans = max(ans,c-i);
    }
    if(ans == -1){
        cout<<"Impossible"<<endl;
        return 0;
    }
    cout<<ans<<endl;
    return 0;
}

持续更新

TAG:SIN_XIII ⑨

猜你喜欢

转载自www.cnblogs.com/SINXIII/p/11041156.html