洛谷P2347 砝码称重 [2017年4月计划 动态规划01]

P2347 砝码称重

题目描述

设有1g、2g、3g、5g、10g、20g的砝码各若干枚(其总重<=1000),

输入输出格式

输入格式:

输入方式:a1 a2 a3 a4 a5 a6

(表示1g砝码有a1个,2g砝码有a2个,…,20g砝码有a6个)

输出格式:

输出方式:Total=N

(N表示用这些砝码能称出的不同重量的个数,但不包括一个砝码也不用的情况)

输入输出样例

输入样例#1:
1 1 0 0 0 0
输出样例#1:
Total=3

暴力算法略,这里只讲dp。
背包问题,每个砝码选或不选,显然01背包。
我们把砝码按照从小到大的顺序依次排开
f[i][j]表示前i个砝码能否组成质量j。
转移:f[i][j] = f[i-1][j] || f[i-1][j-w[i]],w[i]表示第i件物品(砝码)的价值(质量),k为第i件物品(砝码)的数量
常规压缩一维:f[j] = f[j] || f[j-k*w[i]]
代码中做了这样的处理:用i和j来共同控制第i件物品。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>

inline int read()
{
	int x = 0;char ch = getchar();char c = ch;
	while(ch > '9' || ch < '0')c = ch,ch = getchar();
	while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0',ch = getchar();
	if(c == '-')return -1 * x;
	return x;
}

const int INF = 99999999999;

int sum;
int w[7] = {0,1,2,3,5,10,20};
bool f[1010];
int num[10];
int ans;

int main()
{
	for(int i = 1;i <= 6;i ++)
	{
		num[i] = read();
		sum += num[i] * w[i];
	}
	f[0] = true;
	for(int i = 1;i <= 6;i ++)
	{
		for(int j = 1;j <= num[i];j ++)
		{
			for(int k = sum;k >= w[i];k --)
			{
				if(f[k - w[i]])f[k] = true;
			}
		}
	}
	for(int i = 1;i <= sum;i ++)
	{
		if(f[i])ans ++;
	}
	printf("Total=%d", ans);
	return 0;
}

 

posted @ 2017-04-17 15:17  嘒彼小星  阅读(398)  评论(0编辑  收藏  举报