POJ 2642 The Brick Stops Here(01背包问题)

Description
有n种砖块,每种砖块有一个体积c和价格p,先有c次询问,每次询问选取m种砖块使得其平均体积介于cmin和cmax之间,如果不存在合法方案则输出inpossible,存在则输出最小价格
Input
第一行为一整数n表示砖块数量,之后n行每行两个整数v和p分别表示该种砖块的体积和价格,然后是一整数c表示查询次数,之后c行每行三个整数m,cmin,cmax表示一次查询
(1<=n<=200,1<=c<=100,1<=v,p,cmin,cmax<=999,1<=m<=20)
Output
对于每次查询,如果存在从n种砖块中选m块使其平均体积介于cmin和cmax之间的方案则输出最小价格,否则输出impossible
Sample Input
11
550 300
550 200
700 340
300 140
600 780
930 785
730 280
678 420
999 900
485 390
888 800
3
2 500 620
9 550 590
9 610 620
Sample Output
420
impossible
3635
Solution
01背包,dp[i][j]表示选i块砖体积不超过j的最小价格,那么对于每种砖块i我们有
dp[j][k]=max(dp[j][k],dp[j-1][k-v[i]]+p[i]),1<=j<=min(n,20),v[i]<=k<=20000
对于每个查询从dp[m][m*cmin]到dp[m][m*cmax]中找最小值即可,找不到即为impossible
Code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 22222
#define INF 0x3f3f3f3f
int dp[22][maxn],n,v[222],p[222],c,m,cmin,cmax;
int main()
{
    while(~scanf("%d",&n))
    {
        memset(dp,INF,sizeof(dp));
        for(int i=0;i<n;i++)
            scanf("%d%d",&v[i],&p[i]);
        dp[0][0]=0;
        for(int i=0;i<n;i++)
            for(int k=20000;k>=v[i];k--)
            {
                int tn=min(n,20);
                for(int j=1;j<=tn;j++)
                    if(dp[j-1][k-v[i]]!=INF)
                        dp[j][k]=min(dp[j][k],dp[j-1][k-v[i]]+p[i]);
            }
        scanf("%d",&c);
        while(c--)
        {
            scanf("%d%d%d",&m,&cmin,&cmax);
            if(m>n)
            {
                printf("impossible\n");
                continue;
            }
            int ans=INF;
            for(int i=m*cmin;i<=m*cmax;i++)ans=min(ans,dp[m][i]);
            if(ans!=INF)printf("%d\n",ans);
            else printf("impossible\n");
        }
    }
    return 0;
}

你可能感兴趣的:(POJ 2642 The Brick Stops Here(01背包问题))