POJ 1837 (DP)

      题目: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;    
}

  

原文地址:https://www.cnblogs.com/HpuAcmer/p/2446431.html