| Time Limit: 1000MS | Memory Limit: 30000K | |
| Total Submissions: 11436 | Accepted: 7130 |
Description
Input
Output
Sample Input
2 4 -2 3 3 4 5 8
Sample Output
2
题意:一个天平上有C个挂钩,第i个挂钩的位置为C[i],C[i] < 0表示该挂钩在原点的左边,C[i] > 0表示该挂钩在原点的右边;然后给出G个钩码的重量,问有多少种挂法使得天平保持平衡。
分析:当天平平衡时,每向天平上挂一个钩码,天平的状态就会改变,而这个状态可以由若干前一状态获得。
首先定义一个平衡度j的概念
当平衡度j=0时,说明天枰达到平衡,j>0,说明天枰倾向右边(x轴右半轴),j<0则相反
那么此时可以把平衡度j看做衡量当前天枰状态的一个值
因此可以定义一个 状态数组dp[i][j],意为在挂满前i个钩码时,平衡度为j的挂法的数量。
由于距离L[i]的范围是-15~15,钩码重量的范围是w[i]是1~25,钩码数量最大是20
因此最极端的平衡度是所有物体都挂在最远端,因此平衡度最大值为j=15*20*25=7500。原则上就应该有dp[ 1~20 ][-7500 ~ 7500 ]。
因此为了不让下标出现负数,做一个处理,使得数组开为 dp[1~20][0~15000],令7500对应0,则当j=7500时天枰为平衡状态。
/*
dp[i][j]表示用了前i个钩码,天平两端的差值(右端 - 左端)为j时的方案数。
极端情况为所有钩码全部挂在左端的最左边位置,根据题目数据可知此时差值最大为
0 - 15 * 25 * 20 = -7500,所以要加上一个偏移量,用7500对应0,假设钩码数量为G,
则最终答案为dp[G][7500]。
转移方程:dp[i][j + w[i] * l[k]] = Sigma(dp[i-1][j])。
k为第k个挂钩位置
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int dp[21][15005];
int l[21], w[21];
int main() {
int C, G;
while(~scanf("%d%d", &C, &G)) {
for(int i = 1; i <= C; i++)
scanf("%d", &l[i]);
for(int i = 1; i <= G; i++)
scanf("%d", &w[i]);
memset(dp, 0, sizeof(dp)); //达到每个状态的方法数初始化为0
dp[0][7500] = 1; // 0对应7500,挂上前0个钩码后,天枰达到平衡状态7500的方法有1个,就是两端都不挂
for(int i = 1; i <= G; i++) {
for(int j = 0; j <= 15000; j++) {
if(dp[i-1][j]) { // 当放入i-1个钩码时状态j已经出现且被统计过方法数,则直接使用统计结果,否则忽略当前状态j
for(int k = 1; k <= C; k++) {
dp[i][j + w[i] * l[k]] += dp[i - 1][j];
}
}
}
}
printf("%d\n", dp[G][7500]);
}
return 0;
}
原文:http://blog.csdn.net/lyhvoyage/article/details/45064083