dp之混合背包poj1742(推荐)

题意:给你价值为a1,a2.....的货币,每种有c1,c2.......个,求这些货币所能组成的价值小于等于m有多少个.....

思路:很像一道多重背包题?那我一开始的确是用多重背包的思路编写的......TLE了,原来其中隐藏着一个被我忽视的一个问题,当ai*ci>=m时,我们没有必要去拆分ci了,就直接把这种情况当作完全背包处理.......

#include<iostream>

#include<stdio.h>

#include<string.h>

using namespace std;

int dp[100005],t[300][2];

int n,m;

int sum;

void deal1(int x)

{

        for(int j=m;j>=x;j--)

        if(dp[j-x]&&dp[j-x]+x>dp[j]&&dp[j-x]+x-1<=m)

        {

                if(!dp[j])   sum++;

                dp[j]=dp[j-x]+x;

        }

}

int main()

{

      

      while(scanf("%d%d",&n,&m)>0&&(n+m))

      {

           for(int i=1;i<=n;i++)

           {

                   scanf("%d",&t[i][0]);

           }

           memset(dp,0,sizeof(dp));

           dp[0]=1;

           sum=0;

           for(int i=1;i<=n;i++)

           {

                   scanf("%d",&t[i][1]);

                   if(t[i][1]*t[i][0]<m)

                   {

                        int k=1;

                        while(t[i][1]-k>0)

                        {

                            deal1(k*t[i][0]);

                            t[i][1]-=k;

                            k*=2;

                        }

                        deal1(t[i][1]*t[i][0]);

                    }

                    else

                    {

                        for(int j=t[i][0];j<=m;j++)

                        if(dp[j-t[i][0]]&&dp[j]<dp[j-t[i][0]]+t[i][0])

                        {

                            if(!dp[j])   sum++;

                            dp[j]=dp[j-t[i][0]]+t[i][0];

                        } 

                    }

           }

           printf("%d\n",sum);

      }

      return 0;

}

 

你可能感兴趣的:(poj)