Uva674 完全背包求方案数

记忆化搜索。注意输入n的位置,否则Tle。

dp[i][j]表示用前j种硬币组成i分钱时的种类数

那么状态转移方程是:dp[i][j]+=DP(i-k*v[j],j-1)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define ll long long

int dp[8000][5];
int q[5]= {1,5,10,25,50};

int solve(int s,int k)
{
    if(dp[s][k]!=-1) return dp[s][k];
    dp[s][k]=0;
    for(int i=k; i<5 && s>=q[i]; i++)
        dp[s][k]+=solve(s-q[i],i);
    return dp[s][k];
}

int main()
{
    memset(dp,-1,sizeof(dp));
    for(int i=0; i<5; i++)
        dp[0][i]=1;
    int n;
    while(cin>>n)
        cout<<solve(n,0)<<endl;
    return 0;
}

递推的写法,自小向大推:

#include<iostream>
using namespace std;
int n,coin[5]= {1,5,10,25,50};
long long dp[8000]= {1};

int main()
{
    for(int i=0; i<5; i++)
        for(int j=0; j<7500; j++)
            dp[j+coin[i]]+=dp[j];

    while(cin>>n)
        cout<<dp[n]<<endl;
    return 0;
}

 另一种:

#include<stdio.h>
#include<string.h>
#define N 7500
int dp[N][6];
int v[5]= {1,5,10,25,50};
int DP(int i,int j)
{
    if(dp[i][j]!=-1)
        return dp[i][j];
    dp[i][j]=0;
    for(int k=0; i-k*v[j]>=0; k++)
        dp[i][j]+=DP(i-k*v[j],j-1);
    return dp[i][j];
}
int main()
{
    int n;
    memset(dp,-1,sizeof(dp));
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0; i<=n; i++)
            dp[i][0]=1;
        printf("%d\n",DP(n,4));
    }
    return 0;
}

 

posted @ 2016-09-30 11:03  a_clown_cz  阅读(294)  评论(0)    收藏  举报