题意:第一行输入两个数C和G。C表示天平上有几个挂钩,G表示有几个挂码。第二行输入C个挂钩的位置,负数表示在左侧,正数表示在右侧。第三行输入G个挂码的重量。问有几种方法可以使得天平平衡。
要使天平平衡需要左右两端的力矩相同,左右力矩最大值都为20*15*25=7500。把每一个力矩值都作为一个状态,则一侧一共有7500个状态,由于左侧的力矩为0~-7500,所以将状态表示整体增大7500。所以力矩的状态为0~15000,7500时表示左右平衡。达到每种状态时的方案数,与使用的砝码数量有关,所以需要从只有1个挂码到有G个挂码的状态层层转移。
因此可以类似背包问题的方法求解,有状态转移方程dp[i][j+w[i]*v[k]] += dp[i-1][j];,表示当有前i个砝码时,,即第i个砝码是新加入的,砝码i悬挂的位置用k表示有1~C个。我们计算出每种状态j+w[i]*v[k]下的方案数。初始化0个砝码时,到达平衡状态7500时的方案数为1。
AC的代码如下:
#include<iostream>
#include<cstring>
using namespace std;
int dp[21][15010];
int main()
{
int C,G;
int v[26],w[26];
cin >> C >> G;
for(int i=1;i<=C;i++)
{
cin >> v[i];//挂钩位置
}
for(int i=1;i<=G;i++)
{
cin >> w[i];//挂物重量
}
memset(dp,0,sizeof(dp));
dp[0][7500] = 1;
for(int i=1;i<=G;i++)
{
for(int j=1;j<=15000;j++)
{
for(int k=1;k<=C;k++)
{
dp[i][j+w[i]*v[k]] += dp[i-1][j];
}
}
}
cout << dp[G][7500] << endl;
return 0;
}