POJ1837 动态规划 (01背包)

来源:互联网 发布:网络防雷保护器 编辑:程序博客网 时间:2024/06/05 20:57

好了!开始干DP。

话说我已经预感到我dp会弱到一定程度了。预计会先持续干两天的dp。


题目概述:

这道题目是说现在有一个神奇的天平,你的目的是要令他平衡。天平两边长度均为15,每边最多有20个挂钩,一共提供最多20个砝码,要求计算当所有砝码都挂上的时候,能使天平平衡的悬挂方式一共有多少种呢。

算法思想:

不得不承认,即使知道这是一个01背包的题,开始做的时候仍然是不会的,然后找题解,看了好长时间看懂之后自己敲了一遍之后ac。

大意是dp[i][j]的意义是在放进第i个砝码之后,达到平衡值j的可能悬挂方式有多少种。

所谓平衡值,就是以7500为平衡点,左移或者右移动(因为左右移动的最大量为7500,所以设置为7500是刚好不会越界)。

然后dp[i][j]就只跟dp[i][j-g[i]*c[k]]有关了,具体关系是dp[i][j]就是把所有组合的g[i]*c[k]组合起来。这里注意i代表第i个砝码,k代表第k个钩子,因为和两个变量都有关,应该是没有办法把这个01背包转换为一维数组(如果有的话还请教导)。直接做也当然没有问题。

代码部分:

#include <iostream>#include <string.h>using namespace std;int nc, ng;int dp[21][15001]; // dp[i][j]数组,意义为在放入第i个重物之后,所能达到的平衡状态量   // 这里把负数的量也加上了,7500等价于平衡,7500以上相当于右边重,以下相当于左边重int c[21], g[21];int main() {cin >> nc >> ng;for (int i = 1; i <= nc; i++) {cin >> c[i];}for (int i = 1; i <= ng; i++) {cin >> g[i];}memset(dp, 0, sizeof(dp));dp[0][7500] = 1; // 初始化的意义,在没有重物放上的时候,自然为一个方法,初始化为1for (int i = 1; i <= ng; i++) {for (int j = 0; j <= 15000; j++) {if (dp[i - 1][j]) { // 如果之前这种状态不存在,不用计数for (int k = 1; k <= nc; k++) {dp[i][j + c[k] * g[i]] += dp[i - 1][j];}}}}cout << dp[ng][7500] << endl;return 0;}


0 0
原创粉丝点击