最少硬币问题


动态规划的核心是状态和状态转移方程**

  • DAG上的动态规划一定要结合图来思考,要心中有图,或者在纸上画图,谨记!这样可以真正理解!求解状态转移方程的过程其实就是在填写一个表格!把表填好了,所有状态就填好了

d(i)定义为以i开始到0结束的最长/短路


/*

最少硬币问题

Sample Input#
3
23
1 2 5

Sample Output#
6
1 2 3 3 3 3
*/


#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;

#define INF 1000000000

const int maxn=105;
int n;
int S;
int V[maxn];
int d[maxn];


void input()
{
    cin>>n>>S;
    for(int i = 1; i <= n; i++) cin >> V[i];
}

//这里要注意表示dp的状态值: 因为最小值可能是0, 所以不能用0代表没算过,而是用-1代表没算过。INF代表不可达。
int dp(int S)
{
    int &ans=d[S];
    if(ans!=-1) return ans;

    ans=INF;//表示不可达
    for(int i=1;i<=n;i++)
        if(S>=V[i])
        {
            ans=min(dp(S-V[i])+1, ans);
        }
    return ans;
}

void print_ans(int* d, int S){
    for(int i=1;i<=n;i++)
        if(S>=V[i] && d[S-V[i]]+1==d[S])
        {
            cout<<i<< " ";
            print_ans(d, S-V[i]);
            break;
        }
}

int main()
{
    input();
    memset(d, -1, sizeof(d));//-1代表没算过
    d[0]=0;//0的时候,不需要硬币

    int r = dp(S);
    if(r==INF) cout<< "no solution"<<endl;
    else
    {
        cout<< r <<endl;
        print_ans(d, S);
    }
}


posted on 2021-07-28 09:34  katago  阅读(41)  评论(0编辑  收藏  举报