uva 674 Coin Change

DP(DAG上的DP)

题意:给你一个目标金额n,有5种硬币50,25,10,5,1,每种硬币无限个,用这些硬币构成这个目标金额n,有多少种不同的构建方法

看做一个有向图处理:好像11能减去5得到6,那么有向边11--->6,同样11减10可以得到1,那么有有向边11--->1

其实其他就是问n到0有多少条不同的路径。

下面是注意处理的问题

好像6,1+5和5+1是一样的只能算为一种情况。没了防止这种情况我们采用减序构建,好像5511是唯一一种它是减序的,5151这些就不是了

这样做就不会重复,但是有可能漏掉,所以要记录前驱用的是哪一种硬币

这样做不仅能防止重复还能防止遗漏,具体看代码

另外一点,即便是正确的代码,任然可能TLE,为什么呢?因为是多组数据。这题虽然是多组数据,但某些数据的n比较大,它运行一遍后很多比n小的数据也已经计算出来了(这是必须的,因为DP本身符合最优子结构,必须知道子问题的最优解才能构造出原问题的最优解)。所以每组数据之前不要都将dp清为-1,每次都清的话相当于每次都要重头来过。另外数据中可能重复测试同一个数据,这不算坑,这其实是考察了到底明不明白这个问题的本质

#include <cstdio>
#include <cstring>
#define N 7500
const int m[10]={0,50,25,10,5,1};
int dp[N][10];

void dfs(int n , int p)
{
    if(dp[n][p]!=-1)
        return ;
    dp[n][p]=0;
    for(int i=p; i<=5; i++)
    {
        if(n-m[i]>=0)
        {
            dfs(n-m[i] , i);
            dp[n][p]+=dp[n-m[i]][i];
        }
    }
    return ;
}
int main()
{
    int n;
    memset(dp,-1,sizeof(dp));
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1; i<=5; i++)
            dp[0][i]=1;
        dfs(n,1);
        printf("%d\n",dp[n][1]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/scau20110726/p/2832968.html