zoukankan      html  css  js  c++  java
  • 状压dp-poj-1170-Shopping Offers

    题目链接:

    http://poj.org/problem?id=1170

    题目意思:

    购物车里有b种(0=<b<=5)物品,每种物品告诉物品代号c(1=<c<=999),数量为k(1=<k<=5),单价为p.超时有s种优惠方案,每种优惠方案包含n种物品,告诉这n种物品的代号和数量以及打包后的优惠价格。求把购物车的东西买完,最少的花费。

    解题思路:

    离散化+状态压缩dp+背包。

    因为总的物品种数最多只有5种,而且每种物品的数量最多只有5,所以可以用状态压缩处理。六进制压缩,每一位表示一种物品,每一位代表的数表示该物品的个数。然后就是简单的背包处理,要么选不优惠的物品,要么选优惠的物品。

    代码:

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<sstream>
    #include<cstdlib>
    #include<string>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<stack>
    #include<list>
    #include<queue>
    #include<ctime>
    #include<bitset>
    #define eps 1e-6
    #define INF 0x3f3f3f3f
    #define PI acos(-1.0)
    #define ll __int64
    #define LL long long
    #define lson l,m,(rt<<1)
    #define rson m+1,r,(rt<<1)|1
    #pragma comment(linker, "/STACK:1024000000,1024000000")
    using namespace std;
    
    #define Maxn 7800 //6^5=3125个状态
    #define Maxm 120
    int dp[Maxn],ba[7],pri[7],num[Maxm],sp[Maxm],state[Maxm];
    int s;
    
    map<int,int>myp;
    
    bool iscan(int * a,int i) //判断第i种优惠能否选
    {
        int tt[5]={0},tmp=state[i]; //求出该种优惠的各物品个数
        int j=0;
        while(tmp)
        {
            tt[j++]=tmp%6;
            tmp/=6;
        }
        for(int j=0;j<5;j++) //判断是否能选
        {
            if(a[j]<tt[j])
                return false;
        }
        return true;
    }
    int main()
    {
       ba[0]=1;
       for(int i=1;i<=5;i++) //预处理进制的,
            ba[i]=ba[i-1]*6;
        int b;
    
        while(~scanf("%d",&b))
        {
            myp.clear();
            int sta=0;
            for(int i=0;i<b;i++)
            {
                int c,k;
                scanf("%d%d%d",&c,&k,&pri[i]);
                myp[c]=i; //对应物品号 离散化处理
                sta+=k*ba[i]; //最后要达到的状态
            }
            memset(dp,INF,sizeof(dp));//初始化
            dp[0]=0;//最初的状态
            scanf("%d",&s);
            for(int i=1;i<=s;i++)
            {
                scanf("%d",&num[i]);
                int tt=0;
                for(int j=1;j<=num[i];j++)
                {
                    int c,k;
                    scanf("%d%d",&c,&k);
                    tt+=ba[myp[c]]*k;//当前优化方案的状态
                }
                state[i]=tt;
                scanf("%d",&sp[i]);//优惠花费
            }
            for(int i=1;i<=sta;i++)
            {
                int kid[5]={0};
                int tt=i,j=0;
                while(tt) //
                {
                    kid[j++]=tt%6;
                    tt/=6;
                }
                for(int p=0;p<j;p++) //不用优惠的话
                    for(int q=1;q<=kid[p];q++) //对每种可以选不超过该物品数量的个数
                        dp[i]=min(dp[i-ba[p]*q]+pri[p]*q,dp[i]);
                for(int j=1;j<=s;j++)//选择每一种优惠
                {
                    if(i>=state[j]&&iscan(kid,j))//能否选
                        dp[i]=min(dp[i-state[j]]+sp[j],dp[i]);
                }
            }
            //system("pause");
            printf("%d
    ",dp[sta]);//买到这么多物品最小花费
        }
       return 0;
    }
    


  • 相关阅读:
    计网:传输层
    计网:网络层
    codeblocks 的安装与初体验
    二叉排序树的建立
    使用颜色空间进行图像分割
    密码学笔记
    Git笔记
    SVM笔记
    GAN笔记——理论与实现
    leetcode(三)
  • 原文地址:https://www.cnblogs.com/riskyer/p/3348025.html
Copyright © 2011-2022 走看看