动态规划入门第3课,经典DP问题2 --- 背包问题

 

  • 练习1
第1题     方案数 查看测评数据信息

给你n个整数,每个数可选或不选,要求选一些数,使它们的和为S,问有多少种方案?

输入格式

  第一行:2个整数n和s,范围都在[1, 100]。

  第二行:n个整数,每个数范围在[-100, 100]。

输出格式

输出方案数。(答案不超过2^63)

输入/输出例子1

输入:

6 10

3 4 7 8 -1 2 

输出:

  4

样例解释:

  3+7, 3+8-1, 4+7-1, 8+2

样例解释

代码奉上

#include<bits/stdc++.h>
using namespace std;
int n,s,d[10011];
long long f[10001];
int main(){
    cin>>n>>s;
    for(int i = 1;i <= n;i++){
        cin>>d[i];
    }
    sort(d+1,d+n+1);
    int m=n+1;
    for(int i = 1;i <= n;i++){
        if(d[i]>= 0){
            m = i;
            break;
        }
    }
    f[0] = 1;
    for(int i = m;i <= n;i++){
        for(int j = 10000;j >= 0;j--){
            if(f[j] != 0&&(j+d[i]<= 10000)){
                f[j+d[i]]+=f[j];
            }
        }
    }
    for(int i = 1;i < m;i++){
        for(int j = 0;j <=10000;j++){
            if(f[j] != 0&&(j+d[i]>= 0)){
                f[j+d[i]]+=f[j];
            }
        }
    }
    cout<<f[s];
    return 0;
}

第2题     差距最小 查看测评数据信息

给你n个正整数,要求你分成2堆,使它们各自的和尽量相同。问2堆的差距最小是多少?

输入格式

 第一行:1个整数n,范围都在[1, 1000]。

  第二行:n个整数,每个数范围在[1, 100]。

输出格式

输出最小差距。

输入/输出例子1

输入:

  6

  3 4 7 8 1 2 

输出:

  1

样例解释:

  13=3+7+1+2

  12=4+8

样例解释

代码:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int MAX_N = 1005;
const int MAX_SUM = 50005;

int main() {
    int n;
    cin >> n;

    vector<int> nums(n);
    int sum = 0;

    for (int i = 0; i < n; i++) {
        cin >> nums[i];
        sum += nums[i];
    }

    int half_sum = sum / 2; 
    vector<bool> dp(MAX_SUM, false);  
    dp[0] = true;  

    for (int i = 0; i < n; i++) {
        for (int j = half_sum; j >= nums[i]; j--) {
            if (dp[j - nums[i]]) {
                dp[j] = true;  
            }
        }
    }

    int min_diff = sum;  
    for (int j = half_sum; j >= 0; j--) {
        if (dp[j]) {
            min_diff = sum - 2 * j;  
            break;
        }
    }

    cout << min_diff << endl;

    return 0;
}

第3题     打印方案 查看测评数据信息

给你n个正整数,每个数可选或不选,要求选一些数,使它们的和为S,输出任意一种方案。

输入格式

  第一行:2个整数n和s,范围都在[1, 10000]。

  第二行:n个整数,每个数范围在[1, 1000]。

输出格式

输出任意一种方案。如果没有方案,输出-1。

输入/输出例子1

输入:

 6 110

  30 50 100 70 30 40

 

输出:

  30 50 30

样例解释:

  或者 70 40也可以。

样例解释

代码:

#include<bits/stdc++.h>
using namespace std;
long long n,a,s;
long long fa[1000005],b[1000005];
int main()
{
    cin>>n>>s;
    b[0]=1;
    for(int i=1;i<=n;i++){
        cin>>a;
        if(a>s)continue;
        for(int j=s;j>=0;j--)
        {
            if(b[j]!=0&&!fa[j+a])
            {
                b[j+a]++;
                fa[j+a]=a;
            }
        }
    }
    if(b[s]==0)
    {
        cout<<-1;
        return 0;
    }
    while(s!=0)
    {
        cout<<fa[s]<<" ";
        s-=fa[s];
    }
    return 0;
}

 

  • 练习2
第1题     储钱罐 查看测评数据信息

给出储钱罐的重量,每种钱对应的重量和价值,求出储钱罐内至少有多少钱?                    

输入格式

  第一行为一个正整数T,表示T(T<=5)组测试数据。

每组数据:

第一行为两个正整数E,F(1<=E<=F<=10000),表示空的储钱罐的重量和装了钱后的重量。

第二行为一个正整数N(1<=N<=500),表示钱的种类数。

接着的N行每一行有两个正整数P,W(1<=P<=50000, 1<=W<=10000),表示钱的价值与重量。

输出格式

每组测试数据一行一个句子“The minimum amount of money in the piggy-bank is X.”X为至少有多少钱,如果无解,则输出“This is impossible.”(注意有英文句号)

 

输入/输出例子1

输入:

3

10 110

2

1 1

30 50

10 110

2

1 1

50 30

1 6

2

10 3

20 4

输出:

The minimum amount of money in the piggy-bank is 60.

The minimum amount of money in the piggy-bank is 100.

This is impossible.

样例解释

代码

#include <iostream>
#include <vector>
#include <limits>

int findMinimumAmount(int E, int F, int N, std::vector<std::pair<int, int> >& coins) {
    std::vector<int> dp(F + 1, std::numeric_limits<int>::max());
    
    dp[0] = 0;
    for (int j = 0; j < N; j++) {
    	for (int i = 1; i <= F; i++) {
            if (i >= coins[j].second && dp[i - coins[j].second] != std::numeric_limits<int>::max()) {
                dp[i] = std::min(dp[i], dp[i - coins[j].second] + coins[j].first);
            }
        }
    }
    
    return (dp[F-E] != std::numeric_limits<int>::max()) ? dp[F-E] : -1;
}

int main() {
    int T;
    std::cin >> T;
    
    while (T--) {
        int E, F;
        std::cin >> E >> F;
        
        int N;
        std::cin >> N;
        
        std::vector<std::pair<int, int> > coins(N);
        
        for (int i = 0; i < N; i++) {
            std::cin >> coins[i].first >> coins[i].second;
        }
        
        int result = findMinimumAmount(E, F, N, coins);
        
        if (result != -1) {
            std::cout << "The minimum amount of money in the piggy-bank is " << result << "." << std::endl;
        } else {
            std::cout << "This is impossible." << std::endl;
        }
    }
    
    return 0;
}

 

  • 练习3 
第1题     多重背包 查看测评数据信息

给出N种钱币的面值和每种钱币的个数,问要凑出M的钱最少要用多少枚钱币?

例如:N=4,M=40,钱币面值分别为:3,6,8,9 , 个数分别是:10,10,2,1。

答案为:6。

输入格式

  第一行:2个整数N和M,N范围在[1,50],M范围在[1,1000000]。

第二行:N个整数表示每种钱币的面值,每个数范围在[1,100]。

第三行:N个整数表示每种钱币的数量,每个数范围在[1,100000]。

输出格式

  输出最少钱币数。  输出最少钱币数。如果没有方案,输出-1。

输入/输出例子1

输入:

  2 100

  5 8

  20 6

输出:

  17

样例解释

代码:

#include<bits/stdc++.h>
using namespace std;
int N,M,d[510],c[510],ans = 0;
int nn,dd[10000],cc[10000];
int f[10000006];
int main(){
    cin>>N>>M;
    for(int i = 1;i <= N;i++){
        cin>>d[i];
    }
    for(int i = 1;i <= N;i++){
        cin>>c[i];
        if(c[i]>M/d[i]){
            c[i] = M/d[i];
        }
    }
    nn = 0;
    for(int i = 1;i <= N;i++){
        int x = c[i];
        for(int p2 = 1;x > p2;p2*=2){
            dd[++nn] = p2*d[i];
            cc[nn] = p2;
            x -= p2;
        }
        if(x > 0){
            dd[++nn] = x*d[i];
            cc[nn] = x;
        }
    }
    f[0] = 1;
    for(int i = 1;i <= nn;i++){
        for(int j = M-dd[i];j >= 0;j--){
            if(f[j]>0){
                if(f[j+dd[i]] == 0|| f[j+dd[i]]>f[j]+cc[i]){
                    f[j+dd[i]] = f[j]+cc[i];
                }
            }
        }
    }
    ans = f[M]-1;
    cout<<ans;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值