01背包入门题【简单到死】

声明:这些题大多是板子题,HDU的多,新手题都是,题目就不贴了,直接点链接就行

1. HDU - 2026 - Bone Collector

题意:最裸的01背包,给你背包总量和物品数,以及物品的价值和体积,让你求背包装满后的最大价值

参考代码

#include<bits/stdc++.h>
using namespace std;

const int N = 1e3 + 10;
int w[N],v[N],dp[N];
int main(){
    int T;cin>>T;
    while(T--){
        memset(dp,0,sizeof(dp));
        int n,V;cin>>n>>V;
        for(int i = 1;i <= n;i++)cin>>v[i];
        for(int i = 1;i <= n;i++)cin>>w[i];
        for(int i = 1;i <= n;i++){
            for(int j = V;j >= w[i];j--){
                dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
            }
        }
        cout<<dp[V]<<endl;
    }
    return 0;
}

2.HDU - 2546 - 饭卡

题意:给你n个菜的价格,没种菜只能买一次,再给你一个m,表示你卡上的余额,有个规定,就是可以用卡里最后的5元钱去购买所有菜里面最贵的一个菜,问你卡里面最少还剩多少钱
分析:首先贪心的先用5元钱,去买最贵的那一个菜,然后剩余的钱做一个01背包即可,哦对了,如果一开始的钱就小于5元的话就直接输出即可

#include<bits/stdc++.h>
using namespace std;

const int N = 1e3 + 10int dp[N],a[N];
int main(){
    ios_base::sync_with_stdio(0);
    int n,V;
    while(cin>>n&&n){
        memset(dp,0,sizeof(dp));
        for(int i = 1;i <= n;i++)cin>>a[i];
        cin>>V;
        if(V < 5)cout<<V<<endl;
        else{
            sort(a+1,a+n+1);//别忘记
            for(int i = 1;i < n;i++){
                for(int j = V - 5;j >= a[i];j--){
                    dp[j] = max(dp[j],dp[j-a[i]]+a[i]);
                }
            }
            cout<<V-dp[V-5]-a[n]<<endl;
        }
    }
    return 0;
}

3. HDU - 2955 - Robberies

题意:首先看到浮点型的就得注意精度问题了,先给你两个数,一个是最大的“容错度”:P,就是如果这个人被警察抓住的概率大于这个值时就会被抓走,还有个时银行的数目,接下来输入的是每个银行的钱数和各自银行被抓到的概率

分析:因为这个浮点型的,不好直接求,也不能直接把那个所有的容错度都扩大一个倍数,这样理解是不对的,因为得考虑一个容斥,从正面分析有点复杂,不妨以反过来,以获得的钱为重量,以被抓的概率为价值,只要不被抓的概率小于等于(1-p)即可,这里面的概率运算可不是相加啦,而是相乘的,所以状态转移方程就是dp[j] = max{dp[j],dp[j-v[i]]*w[i]},最后从最大的开始枚举,只要大于等于(1-p)就输出即可

参考代码

#include <bits/stdc++.h>
using namespace std;
#define EPS 0.00000000001
struct node{
    int v;double w;
}a[5007];
double dp[5007];
int main(){
    ios_base::sync_with_stdio(false);
    int T;cin>>T;
    while(T--){
        memset(dp,0,sizeof(dp));dp[0] = 1;
        int n,sum_v = 0;double V;
        cin>>V>>n;
        V = 1 - V;
        for(int i = 0;i < n;i++){
            cin>>a[i].v>>a[i].w;
            a[i].w = 1 - a[i].w;
            sum_v += a[i].v;
        }
        for(int i = 0;i < n;i++){
            for(int j = sum_v;j >= a[i].v;j--){
                dp[j] = max(dp[j],dp[j-a[i].v]*a[i].w);
            }
        }
        for(int i = sum_v;i >= 0;i--){
            if(V - dp[i] < EPS){
                cout<<i<<endl;
                break;
            }
        }
    }
    return 0;
}

4. HDU - 1203 - I NEED A OFFER!

题意:与上一题类似,这次是求个最小值而已 max ->min,反过来求就行了,又是浮点数,而且最后那个’%’,我wa了三次,mdzz..

参考代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10007;
int main(){
    int v[maxn];
    double dp[maxn],p[maxn];
    int n,m;
    while(cin>>n>>m && n+m){
        for(int i = 0;i <= n;i++)dp[i] = 1.0;
        for(int i = 0;i < m;i++){
            cin>>v[i]>>p[i];
            p[i] = 1 - p[i];
        }
        for(int i = 0;i < m;i++){
            for(int j = n;j >= v[i];j--){
                dp[j] = min(dp[j],dp[j-v[i]]*p[i]);
            }
        }
        printf("%.1f%%\n",(1-dp[n])*100);
    }
    return 0;
}

5. HDU - 1171 - Big Event in HDU

题意:给你n组数据,包括两个值,一个设备的价值,和相应的数目,让你分成两份,尽可能的相等,最后输出两个数,保持前面那个数大于等于后面那个数
分析: 就是一个看似01背包的题,用另一个数组把所有值都包含,直接对sum/2 进行01背包即可

#include<bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;
int dp[N];
vector<int> a;
int main(){
//  ios_base::sync_with_stdio(0);
    int n,t,x;
    while(cin>>n && n > -1){
        int sum = 0;
        a.clear();
        memset(dp,0,sizeof(dp));
        for(int i = 0;i < n;i++){
            cin>>x>>t;
            sum += x*t;
            while(t--) a.push_back(x);
        }
        int sum1 = sum/2;
        for(int i = 0;i < a.size();i++){
            for(int j = sum1;j >= a[i];j--){
                dp[j] = max(dp[j],dp[j-a[i]]+a[i]);
            }
        }
        printf("%d %d\n",max(dp[sum1],sum-dp[sum1]),min(dp[sum1],sum-dp[sum1]));
    }
    return 0;
}

待更新…………

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值