poj1837 balance

//题意:先给定两个值c,g分别代表:在臂长为15(两边均15)的天平上的总的挂钩数和砝码个数。下一行为c个数字代表天平的哪些位置有挂钩,例如-2代表据天平中心向左2个距离 ;2代表据天平中心向右2个距离。最后一行有g个数字代表每个砝码的重量。题目要求是两边天平保持平衡的挂法。

//思路:天平最极端的情况为 +15*max_g*max_c,-15*max_g*max_c,那么将此题转换为一个dp问题,这里每放一个砝码根据挂钩个数的不同会有多个状态,那么当前状态必可由上一个状态转化。申请dp[i][j]状态数组,他代表当放上i个砝码后处于j这个状态的次数,-7500 <= j >=7500, dp[i][0]此时相当于处于平衡状态,可以将这个数组抽象为数轴,j<0天平向左倾斜,j>0天平向右倾斜。因为数组下标为正,则将j转化为0~15000, j==7500时代表之前的dp[i][0]. 那么此时要注意挂i个砝码生成的新的状态由i-1个状态转化 则dp[i][j] =dp[i][j] + dp[i-1][j];这个其实挺好理解的,1)若有i-1个砝码到达dp[i-1][j]这个状态共有num种方式,那么在要挂一个砝码到达j状态时必然也是num种;  2)但是挂这一个砝码有不同的位置,则可能在不同位置挂这一个砝码时得到相同的状态j则要将当前状态值加上j状态此时究竟有多少种可能而不是dp[i][j]=dp[i-1][j],则dp[i][j] =dp[i][j] + dp[i-1][j]是j状态下的方程,那么对于要挂一个重量w的砝码在力臂为x情况下而生成一种新的状态j即,dp[i][j+w*x] = dp[i][j+w*x] + dp[i-1][j] ;见代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int x[30];
int w[30];
int dp[30][15010];

int main()
{
    int c, g;
    while(scanf("%d%d", &c, &g) != EOF){

     
        memset(x, 0, sizeof(x));
        memset(w, 0, sizeof(w));
        memset(dp, 0, sizeof(dp));
        dp[0][7500] = 1;

       
        for(int i = 1; i <= c; i++)
            scanf("%d", &x[i]);
        for(int i = 1; i <= g; i++)
            scanf("%d", &w[i]);

    
        for(int i = 1; i <= g; i++){
            for(int j = 0; j <= 15000; j++){
                if(dp[i-1][j]){
                    for(int k = 1; k <= c; k++){
                        dp[i][j+w[i]*x[k]]+=dp[i-1][j];    //这里如上面蓝色部分推的理解很重要
                    }
                }
            }
        }

        
        printf("%d\n", dp[g][7500]);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值