【动态规划】Coin Change 2硬币问题(2)

Description
有n种硬币,面值分别为V1,V2,V3,…..Vn,每种都有无限多。
给定非负整数S,可以选用多少个硬币,使得面值之和恰好为S?
输出硬币数目的最小值和最大值。1<=n<=100, 0<=S<=10000,1<=Vi<=S。

Input Data
输入有三行:第一行一个整数S;第二行一个整数n,表示硬币种数;第三行n个整数,表示硬币面值

Output Data
输出四行:前两行为最小值,和组成最小值的方案;后两行为最大值和方案。若有多种方案,输出字典序最小的(即序号尽量小的),方案中之只包含面值的序号。

Input / Output Sample
6
4
3 1 2 5
Output Sample
2
1 1
6
2 2 2 2 2 2

————————————————分割の线————————————————
分析
这是一道dp的入门好题。显然是一种无限背包的变形题(将最大和最小相融合),除此之外还要注意opt的记录。
对于背包不熟悉的,可以尝试一下[luoguP1060]开心的金明

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,s;
int v[200];//不同硬币的面值
int f[10010],opt[10010][2];
//f[i]表示距离目标面值差i的方案数
//opt[i][0]表示从转移到i点前原始状态,opt[i][1]表示转移时使用的硬币的序号
void write(int x)
{
    if(opt[x][0]!=s) //如果当前状态不为初始状态时,再次通过opt进行回溯
    {
        printf("%d ",opt[x][1]);
        write(opt[x][0]);
        return ;
    }
    else printf("%d",opt[x][1]);//注意省略文末空格
    return ;
}
int main()
{
    cin>>s>>n;
    for(int i=1;i<=n;i++)
        scanf("%d",&v[i]);
    memset(f,-1,sizeof(f));//将除初始状态之外的其他状态,全标记为未赋值(-1)
    memset(opt,0,sizeof(opt));//其实是不需要的
    f[s]=0;
    for(int i=n;i>=1;i--)//从后往前枚举,注意取的是≥(>=),如此可以有效更新字典序比它大的原始序列。想一下这是为什么?
        for(int j=s;j>=v[i];j--)//注意是无限背包问题
        {
            if(f[j]!=-1)
                if(f[j-v[i]]==-1||f[j-v[i]]>=f[j]+1)//刷表法,从当前状态出发更新f[j-v[i]]的值
                {
                    opt[j-v[i]][0]=j,opt[j-v[i]][1]=i;
                    f[j-v[i]]=f[j]+1;
                }
        }
    printf("%d\n",f[0]);//输出方案数
    write(0);//回溯输出使用硬币的序列
    cout<<endl;
    //如下同上
    memset(f,-1,sizeof(f));
    memset(opt,0,sizeof(opt));
    f[s]=0;
    for(int i=n;i>=1;i--)
        for(int j=s;j>=v[i];j--)
        {
            if(f[j]!=-1)
                if(f[j-v[i]]==-1||f[j-v[i]]<=f[j]+1)
                {
                    opt[j-v[i]][0]=j,opt[j-v[i]][1]=i;
                    f[j-v[i]]=f[j]+1;
                }
        }
    printf("%d\n",f[0]);
    write(0);
    cout<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xyc1719/article/details/79956310