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; }