1068 Find More Coins

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




你可能感兴趣的:(1068 Find More Coins)