题解 | #最小邮票数#

最小邮票数

http://www.nowcoder.com/practice/83800ae3292b4256b7349ded5f178dd1

#include <cstdio>
#include <iostream>
#include <cstring>
#include <climits>

using namespace std;

//这题如何类比0-1背包?
//个人思路:“价值最大”在这题转化为“邮票张数最小” 可以这样转化:每张邮票价值为-1 完美
//0-1背包中,是可以不塞满的,这题必须塞满,这个怎么办?这是真正的难点。

const int MAXM = 100 + 10;
const int MAXN = 20 + 2;
const int INF = INT_MAX;

int dp[MAXM];
int w[MAXN];//存“分数” 
int v[MAXN];//存“-1”

int main(){
	memset(v, -1, sizeof(v));
	int m, n;
	while(scanf("%d%d", &m, &n) != EOF){
		memset(dp, 0, sizeof(dp));
		for(int i=1; i<=n; i++){
			scanf("%d", &w[i]);
		}
		for(int i=1; i<=n; i++){
			for(int j=m; j>=w[i]; j--){
				int a = dp[j];
				int b = dp[j-w[i]] + v[i];//注意一个逻辑。dp[j-w[i]]是凑成了j-w[i]分,而v[i]对应w[i]分,加起来刚好是j 
				//所以单论这里是不用去做总和检验的。
				//那总和是怎么保证的呢? 个人思路:检测“初始状态”
				if(a == 0){//在遇到第i个元素前,都没有可行的放法 那一旦b可行,a就应该让步 
					a = -INF;
				}
				if(dp[j-w[i]] == 0){//说明对应容量j-w[i],用前i-1个元素没有放法,只能期待w[i]本身就等于j 
					if(w[i] == j){
						;//b就可以维持原样 
					}else{
						b = -INF;//不可行 
					}
				} 
				dp[j] = max(a, b);
				if(dp[j] == -INF){//意味着“不可行” 
					dp[j] = 0;
				}//所以最终其实用不到vector
			}
		}
		printf("%d\n", -dp[m]);
	}
	return 0;
}
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务