咳咳,DP 问题
ref1:
https://github.com/biaobiaoqi/CPractice/blob/master/PAT/advancedlevel/APAT1068.cpp
ref2:
http://tech-wonderland.net/blog/pat-1068-find-more-coins.html
1: ref都是用循环就求出DP的二维数组了, 第一次见识,我仍然用备忘录的方法,递归求解
int solu[10000+5][100+5]; // solu[i][j]表示从前i个硬币任意挑选,在其面值和不超过j的条件下,能达到的最大的值
实际在求solu[i][j],也没有逻辑来限制solu[i][j] 不超过 j(除了判断coin[i]>j),只要求出最大值就行了,如果solu[n]
[m]的值大于m,说明so solution;
不用考虑solu[n-1][m] < m < solu[n][m]的情况下,是否要修正solu[n-1][m]的值的问题,想多了;
只要一味地去求对于当前条件(i和j)下的最大值就行了!
2:给coin按面值排成倒序保证了输出字典顺序,想不通!
3:关于备忘录解法:
int dp(int i , int j ){//这是用备忘录形式的DP if(solu[i][j] > -1 ){//1:已经计算过值了 return solu[i][j]; } if(i == 0 || j == 0){ solu[i][j] = 0; return 0; } int x = dp(i-1, j ); int y = dp(i-1, j-coin[i] ) + coin[i];//coin下标是从0开始的 if(x> y || coin[i] > j){//2:coin[i]太大了,超过j, 当然不选中,保持从前i-1个硬币中达到的最大值 solu[i][j] = x; }else{ solu[i][j] = y; included[i][j] = 1;//3:用inluded[][]记录路径 } return solu[i][j]; }
4:included[][]数组用来输出路径,想死也想不到啊; 输出时根据included模拟实现了
for(int i = n; i >0; i--){ if(included[i][max] == 1){//在达到max值的过程中,每选取一个数coin[i],要达到的max-coin[i] printf("%d", coin[i]); max -= coin[i]; if(max == 0 ){ break; } } }
5: 关于qsort排序的参数,因为要排序的是coin[1...N],不是从coin[0]开始,所以
qsort(coin + 1, n, sizeof(int), cmp);// qsort第一个参数加1就是从coin[1]...[n]排序了
#include <stdio.h> #include <algorithm> #include <string.h> using namespace std; int n, m; int coin[10000+5]; int cmp(const void * a, const void * b){//要倒序,fuck and why?!!!!! return *(int *)b - *(int *)a; } int solu[10000+5][100+5];// solu[i][j]表示从前i个硬币任意挑选,在其面值和不超过j的条件下,能达到的最大的值 int included[10000+5][100+5];//included[i][j]表示在从前i个硬币中挑选,组成最大值时,coin[i]是否被选中 int dp(int i , int j ){//这是用备忘录形式的DP if(solu[i][j] > -1 ){//1:已经计算过值了 return solu[i][j]; } if(i == 0 || j == 0){ solu[i][j] = 0; return 0; } int x = dp(i-1, j ); int y = dp(i-1, j-coin[i] ) + coin[i];//coin下标是从0开始的 if(x> y || coin[i] > j){//2:coin[i]太大了,超过j, 当然不选中,保持从前i-1个硬币中达到的最大值 solu[i][j] = x; }else{ solu[i][j] = y; included[i][j] = 1;//3:用inluded[][]记录路径 } return solu[i][j]; } int main(){ freopen("in.txt","r",stdin); scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++){ scanf("%d", &coin[i]); } qsort(coin + 1, n, sizeof(int), cmp);// qsort第一个参数加1就是从coin[1]...[n]排序了, amazing!!! memset(solu, -1, sizeof(solu));//-1表示还未求值 memset(included, 0, sizeof(included)); if(dp(n, m ) == m){ int max = m; bool nonFirst = false; for(int i = n; i >0; i--){ if(included[i][max] == 1){//在达到max值的过程中,每选取一个数coin[i],要达到的max-coin[i] if(!nonFirst){ nonFirst = true; }else{ printf(" "); } printf("%d", coin[i]); max -= coin[i]; if(max == 0 ){ break; } } } }else{ printf("No Solution\n"); } return 0; }