PAT(甲级)渡劫(二十六)-Find More Coins (30)

PAT(甲级)渡劫(二十六)-Find More Coins (30)

在这里插入图片描述
在这里插入图片描述

算法思想:

题意:从n个硬皮中选取方案,使得总和价值正好为m,如果有多种,方案为排列最小的那个。

可以把硬币看成w=v(即容量=价值)的物品,现在要选取这些物品放入到容量为m的背包中,求能装的最大价值。
如果最大价值恰好等于容量m,那么方案则是可行的,否则输出No Solution。
由于要输出排列最小的方案,所以先将硬币按价值从大到小排列,相当于我先装大的,再装小的。
接着用01背包的方法求dp[j]。
chosen[i][j]数组表示背包里容量为j的时候,是否含有第i个物品,用于最后序列的输出。

代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;
const int maxn = 10000+4;
const int maxv = 105;

int coins[maxn];
int dp[maxv];   // dp[v]表示:总和加起来=v的序列中最后一个值最小为多少。
int chosen[maxn][maxv]; // choosen[i][j]数组表示背包里容量为j时,是否含有第i个物品,用于最后序列的输出
int ans[maxn];
int cnt = 0;

bool cmp(int a,int b){
    return a > b;
}

int main(){
    //freopen("in.txt","r",stdin);
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i = 0 ; i < n ; i++){
        scanf("%d",&coins[i]);
    }
    sort(coins,coins+n,cmp);    // 按从大到小的顺序排序
    dp[0] = 0;  // 边界
    for(int i = 0 ; i < n ; i++){
        for(int j = m ; j >= coins[i] ; j--){
            if(dp[j] <= dp[j-coins[i]]+coins[i]){
                dp[j] = dp[j-coins[i]]+coins[i];
                chosen[i][j] = 1;
            }
        }
    }
    if(dp[m] != m){
        printf("No Solution");
    }else{
        int v = m,idx = n-1;
        while(v){
            if(chosen[idx][v]){
                ans[cnt++] = coins[idx];
                v-=coins[idx];
            }
            idx--;
        }
        printf("%d",ans[0]);
        for(int i = 1 ; i < cnt ; i++)
            printf(" %d",ans[i]);
    }
    return 0;
}
运行结果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值