L3-001 凑零钱 (30分) —— 记录路径的0/1背包

202 篇文章 6 订阅
该博客主要讨论了一道关于动态规划的算法问题,涉及寻找使用硬币找零的字典序最小路径。文章通过01背包优化思路,详细解释了如何利用贪心策略和动态规划在O(nm)的时间复杂度内解决这个问题。内容包括问题描述、解决方案、代码实现及思路解析。
摘要由CSDN通过智能技术生成

This way

题意:

在这里插入图片描述

题解:

以前好像做到过类似的题目,当然那个时候是 n 2 m n^2m n2m的时间复杂度过的,这个题目的话要优化
首先可以确认的是01背包,那么怎么记录路径?用pre表示当前是从哪里转移过来的
那么如何让字典序最小?先用大的货币,然后再做小的货币,这样子pre就可以贪心地取最后到达的地方,因为字典序来说,越前面越小越优
那么pre[i][j]表示第i个硬币必取,当前有j块钱的时候,是从哪里转移过来的
那么很明显pre[i][j]不一定是从pre[i-1][j]转移过来的,那么如果每次都去找的话,时间复杂度就会变成 n m n^m nm,那么我们需要考虑优化,然后我们又知道,它因为字典序要最小,所以越后面的硬币一定是越优的,那么我们用mi[i]表示到现在为止,用i块钱的最优转移是mi[i]行(也就是必取第i个硬币)
那么就可以直接从mi转移到当前位置

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5,M=205;
int a[N],mi[N];
struct node{
    int i,j;
};
node pre[N][M];
bool cmp(int x,int y){return x>y;}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    m++;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    sort(a+1,a+1+n,cmp);
    memset(mi,-1,sizeof(mi));
    mi[1]=0;
    pre[0][1]={-1,-1};
    for(int i=1;i<=n;i++){
        for(int j=m+1;j>a[i];j--){
            if(~mi[j-a[i]]){
                pre[i][j]={mi[j-a[i]],j-a[i]};
                mi[j]=i;
            }
        }
    }
    if(mi[m]==-1)return 0*printf("No Solution\n");
    int fi=mi[m],se=m;
    while(se!=1){
        printf("%d%c",se-pre[fi][se].j,pre[fi][se].j==1?'\n':' ');
        int nfi=pre[fi][se].i;
        se=pre[fi][se].j;
        fi=nfi;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值