好了!开始干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; // 初始化的意义,在没有重物放上的时候,自然为一个方法,初始化为1 for (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; }