POJ 1837 Balance (动态规划)

        这是一道典型的动态规划题,一开始很难想到怎样记录状态,但是我们发现要求的是平衡的种类数,因此我们可以想到的是dp数组保存的是平衡的时候的种类数。但是我们为了想到一个比较好的能够保存状态并且展现最终的种类数的记录状态的方式,于是我们尝试使用dp[i][j]表示使用了前i个物品后,使得天平左右相差为j的时候的种类数。

        于是我们很容易得到状态转移的过程,dp[i]可以由dp[i-1]的一个值,放第i个物品在挂钩的某个位置,转移到dp[i][j],dp[i][j]就是所有这些满足合法条件的dp[i-1]的总和。

        我们还要小心的一点就是,我们当我们发现左边比右边重的时候,j是负数,因此我们考虑到j的范围为7500,因此我们很容易想到对这些下标j都同时加上一个7500.然后根据状态转移方程进行转移就可以了。

        注意初始状态本来应该为dp[0][0]=1,但是我们加了一个偏移量之后就要相应的将偏移量加到j上面去!!!

下面是AC代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
using namespace std;
const int det=7500;
const int Max=16000;
int dp[22][Max];
int main()
{
    int x[22],m[22],temp,t;
    int c,g,i,j,k;
    while(scanf("%d %d",&c,&g)!=EOF)
    {
        for(i=1;i<=c;i++)
            scanf("%d",&x[i]);
        for(i=1;i<=g;i++)
            scanf("%d",&m[i]);
        memset(dp,0,sizeof(dp));
        dp[0][det+0]=1;
        for(i=1;i<=g;i++)
        {
            for(j=0;j<=2*det;j++)
            {
                temp=0;
                for(k=1;k<=c;k++)
                {
                    int t=m[i]*x[k]+det;
                    if(j-t+det>=0)
                    {
                        temp+=dp[i-1][j-t+det];
                    }
                }
                dp[i][j]=temp;
            }
        }
        printf("%d\n",dp[g][det]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值