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;

}

 

你可能感兴趣的:(change)