题目:http://poj.org/problem?id=1837
一个天平,两个臂,两边有若干挂钩,给若干重物,把重物挂在挂钩上,使天平平衡,所有重物要用完,问一共有多少种方法?
首先,自定义平衡度(不知有没有):∑重量*力矩
显然平衡度为0时是平衡的。
定义balance[i][j]为用完前面 i 个重物,达到平衡度 j 的方法数,为出现负数啊!怎么办?因为最大的挂钩位置15,最大重物重量25,最大的重物数量20,所以最大的平衡度是7500(都在最右边),同理最小的平衡度是-7500,为避免下标为负数,就+7500,于是可定义全局数组 balance[21][15001]。初始平衡态为 balance[0][7500],0表示没放物体,7500是平衡的,因为逆着转回去就是0了撒!
既然是动态规划,就要找到子问题,定义状态,找到状态转移方程。
状态:balance[i][j]是用完前面 i 个重物,达到平衡度 j 的方法数
子问题:要知道balance[i][j] 只需知道没放第 i 个重物时的过渡状态(就是通过把第i个重物放在某个挂钩可以达到平衡度j),或者转化下:balance[i-1][j]把第i个重物放到某个位置达到的新的状态(便于代码实现)
状态转移方程: balance[i][ j+hook[k]*weight[i] ] += balance[i-1][j]; (i表示重物的下标,k表示挂钩的下标,j表示平衡度)
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int balance[21][15001],hook[21],weight[21];
int main()
{
int h,w,i,j,k;
while(scanf("%d%d",&h,&w) != EOF )
{
for(i = 1 ; i <= h ; ++i)
scanf("%d",hook+i);
for(i = 1 ; i <= w ; ++i)
scanf("%d",weight+i);
/*
初始化
*/
memset(balance,0,sizeof(balance));
balance[0][7500] = 1;
/*
动态规划
*/
for(i = 1 ; i <= w ; ++i)//遍历重物
{
for(j = 15000 ; j >= 0 ; --j)//平衡度
{
if(balance[i-1][j])
for(k = 1 ; k <= h;++k)//求下一状态
balance[i][ j+hook[k]*weight[i] ] += balance[i-1][j];
}
}
printf("%d\n",balance[w][7500]);
}
//system("pause");
return 0;
}