1. 程式人生 > >01揹包入門題【簡單到死】

01揹包入門題【簡單到死】

宣告:這些題大多是板子題,HDU的多,新手題都是,題目就不貼了,直接點連結就行

題意:最裸的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; }

題意:給你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; }

題意:首先看到浮點型的就得注意精度問題了,先給你兩個數,一個是最大的“容錯度”: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;
}

題意:與上一題類似,這次是求個最小值而已 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;
}

題意:給你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;
}

待更新…………