入門經典--硬幣問題dp遞歸加遞推

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
int v[101],s,n,mini[10001],maxn[10001],visi[10001];

int MAX(int a,int b)
{
    return a>b?a:b;
}
int MINI(int a,int b)
{
    return a<b?a:b;
}

int dp_mini(int ss)
{
    if(visi[ss]) return mini[ss];
    visi[ss] = 1;
    mini[ss] = (1<<30);
    for(int i=1;i<=n;++i)
        if(ss>=v[i]) mini[ss] = MINI(mini[ss],dp_mini(ss-v[i])+1);
    return mini[ss];
}

int dp_max(int ss)
{
    if(visi[ss]) return maxn[ss];
    visi[ss] = 1;
    maxn[ss] = -(1<<30);
    for(int i=1;i<=n;++i)
        if(ss >= v[i]) maxn[ss] = MAX(maxn[ss],dp_max(ss-v[i])+1);
    return maxn[ss];
}

int solve_mini()
{
    for(int i=1;i<=s;++i)
        mini[i] = (1<<30);
    mini[0] = 0;
    for(int i=1;i<=s;++i)
        for(int j=1;j<=n;++j)
            if(i >= v[j]) mini[i] = MINI(mini[i],mini[i-v[j]]+1);
    return mini[s];
}

int solve_max()
{
    for(int i=1;i<=s;++i)
        maxn[i] = -(1<<30);
    maxn[0] = 0;
    for(int i=1;i<=s;++i)
        for(int j=1;j<=n;++j)
            if(i>=v[j]) maxn[i] = MAX(maxn[i],maxn[i-v[j]]+1);
    return maxn[s];
}

int main()
{
    scanf("%d %d",&n,&s);
    for(int i=1;i<=n;++i)
        scanf("%d",&v[i]);
    memset(visi,0,sizeof(visi));
    visi[0]=1;//這一步初始化很關鍵,原書並未強調
    int mini1 = dp_mini(s);
    memset(visi,0,sizeof(visi));
    visi[0]=1;
    int max1 = dp_max(s);
    int mini2 = solve_mini();
    int max2 = solve_max();
    printf("%d %d\n%d %d\n",mini1,max1,mini2,max2);

    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章