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;
}


你可能感兴趣的:(c)