zoukankan      html  css  js  c++  java
  • 洛谷P2732 商店购物 Shopping Offers

    P2732 商店购物 Shopping Offers

      • 23通过
      • 41提交
    • 题目提供者该用户不存在
    • 标签USACO
    • 难度提高+/省选-

      讨论  题解  

    最新讨论

    • 暂时没有讨论

    题目背景

    在商店中,每一种商品都有一个价格(用整数表示)。例如,一朵花的价格是 2 zorkmids (z),而一个花瓶的价格是 5z 。为了吸引更多的顾客,商店举行了促销活动。

    题目描述

    促销活动把一个或多个商品组合起来降价销售,例如:

    三朵花的价格是 5z 而不是 6z, 两个花瓶和一朵花的价格是 10z 而不是 12z。 编写一个程序,计算顾客购买一定商品的花费,尽量利用优惠使花费最少。尽管有时候添加其他商品可以获得更少的花费,但是你不能这么做。

    对于上面的商品信息,购买三朵花和两个花瓶的最少花费的方案是:以优惠价购买两个花瓶和一朵花(10z),以原价购买两朵花(4z)。

    输入输出格式

    输入格式:

    输入文件包括一些商店提供的优惠信息,接着是购物清单。(最多有5种商品)

    第一行 优惠方案的种类数(0 <= s <= 99)。

    第二行..第s+1 行 每一行都用几个整数来表示一种优惠方式。第一个整数 n (1 <= n <= 5),表示这种优惠方式由 n 种商品组成。后面 n 对整数 c 和 k 表示 k (1 <= k <= 5)个编号为 c (1 <= c <= 999)的商品共同构成这种优惠,最后的整数 p 表示这种优惠的优惠价(1 <= p <= 9999)。优惠价总是比原价低。

    第 s+2 行 这一行有一个整数 b (0 <= b <= 5),表示需要购买 b 种不同的商品。

    第 s+3 行..第 s+b+2 行 这 b 行中的每一行包括三个整数:c,k,p。 c 表示唯一的商品编号(1 <= c <= 999),k 表示需要购买的 c 商品的数量(1 <= k <= 5)。p 表示 c 商品的原价(1 <= p <= 999)。最多购买 5*5=25 个商品。

    输出格式:

    只有一行,输出一个整数:购买这些物品的最低价格。

    输入输出样例

    输入样例#1:
    2
    1 7 3 5
    2 7 1 8 2 10
    2
    7 3 2
    8 2 5
    输出样例#1:
    14

    说明

    题目翻译来自NOCOW。

    USACO Training Section 3.3

    分析:这道题和斗地主很像,目的就是要把所有的物品买完,也就相当于把牌出完,给你几种优惠方式相当于牌的组合,让我不禁联想到了noip2015斗地主,我们可以搜索每一种优惠方式能不能行,如果可以就继续,不行就搜索下一种优惠方式,如果都不行,那么就只能一个一个的买了,为了避免重复,用了一个hash,但是这样还是超时了.听raffica神犇说如果倒着输入会有惊喜,然后发现,还是T了5个点,只能想其他的办法.

           发现搜索是从已知状态扩展到未知状态,如果是用已知状态来更新未知状态呢?这就是dp了,枚举优惠方式,如果可行,则根据优惠方式所需的物品来推得当前的状态,f[a][b][c][d][e] = f[a - i][b - j][c - k][d - l][e - m] + p,i,j,k,l,m都是所需的物品,p是钱数,这其实就是完全背包.

    49分代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    int s,b,vis1[10000],need[100],neednum[10000],needmoney[10000],ans = 10000000,vis[6][6][6][6][6],hashh[3000000],tot;
    
    struct node
    {
        int num[10000];
        int money;
    }a[110];
    
    void dfs(int m,int n)
    {
        int flag = 0;
        for (int i = 1; i <= n; i++)
        {
            //printf("%d
    ", neednum[need[i]]);
            if (neednum[need[i]] != 0)
            {
                flag = 1;
                break;
            }
        }
        if (flag == 0)
            if (ans > m)
            {
                ans = m;
                return;
            }
        if (hashh[vis[neednum[need[1]]][neednum[need[2]]][neednum[need[3]]][neednum[need[4]]][neednum[need[5]]]] != 0 && hashh[vis[neednum[need[1]]][neednum[need[2]]][neednum[need[3]]][neednum[need[4]]][neednum[need[5]]]] == m)
            return;
            vis[neednum[need[1]]][neednum[need[2]]][neednum[need[3]]][neednum[need[4]]][neednum[need[5]]] = ++tot;
            hashh[vis[neednum[need[1]]][neednum[need[2]]][neednum[need[3]]][neednum[need[4]]][neednum[need[5]]]] = m;
            for (int i = 1; i <= s; i++)
            {
                int flag1 = 0;
                for (int j = 1; j <= n; j++)
                    if (neednum[need[j]] < a[i].num[need[j]])
                    {
                        flag1 = 1;
                        break;
                    }
                if (flag1 == 0)
                {
                    //printf("%d
    ", i);
                    for (int j = 1; j <= n; j++)
                        neednum[need[j]] -= a[i].num[need[j]];
                    dfs(m + a[i].money, n);
                    for (int j = 1; j <= n; j++)
                        neednum[need[j]] += a[i].num[need[j]];
                }
            }
            for (int i = 1; i <= n; i++)
                if (neednum[need[i]] >= 1)
                {
                    neednum[need[i]]--;
                    dfs(m + needmoney[need[i]], n);
                    neednum[need[i]]++;
                }
            return;
    }
    
    
    int main()
    {
        scanf("%d", &s);
        for (int i = s; i >= 1; i--)
        {
            int n,t = 0,p;
            scanf("%d", &n);
            for (int j = 1; j <= n; j++)
            {
                int k, c;
                scanf("%d%d", &c, &k);
                a[i].num[c] = k;
            }
            scanf("%d", &p);
            a[i].money = p;
        }
        scanf("%d", &b);
        int t = 0;
        for (int i = 1; i <= b; i++)
        {
            int c, k, p;
            scanf("%d%d%d", &c, &k, &p);
            if (!vis1[c])
            {
                vis1[c] = 1;
                need[++t] = c;
            }
            neednum[c] = k;
            needmoney[c] = p;
        }
        /*
        for (int i = 1; i <= s; i++)
        {
            for (int j = 1; j <= t; j++)
                printf("%d需要%d
    ", need[j], a[i].num[need[j]]);
            printf("钱%d
    ", a[i].money);
        }
        for (int i = 1; i <= t; i++)
            printf("%d %d %d
    ", need[i], neednum[need[i]], needmoney[need[i]]);
            */
        dfs(0,t);
        printf("%d
    ", ans);
        //while (1);
    
        return 0;
    }

    AC代码(显然不是我的):

    #include<cstdio>  
    #include<iostream>  
    #include<algorithm> 
    int n;
    int i, j, k, l, m, z;
    struct haha
    {
        int n;
        int k[6];
        int p;
    }a[200];
    int nn;
    int d[1000];
    int t;
    int ai, bi, ci;
    int f[6][6][6][6][6];
    int x[6];
    using namespace std;
    int main()
    {
        scanf("%d", &n);
        for (i = 1;i <= n;i++)
        {
            scanf("%d", &a[i].n);
            for (j = 1;j <= a[i].n;j++)
            {
                scanf("%d%d", &ai, &bi);
                if (d[ai] == 0)
                {
                    t++;
                    d[ai] = t;
                }
                a[i].k[d[ai]] = bi;
            }
            scanf("%d", &a[i].p); 
        }
        scanf("%d", &nn);
        for (i = 1;i <= nn;i++)
        {
            scanf("%d%d%d", &ai, &bi, &ci);
            if (d[ai] == 0)
            {
                t++;
                d[ai] = t;
            }
            x[d[ai]] = bi;
            n++;
            a[n].n = 1;
            a[n].k[d[ai]] = 1;
            a[n].p = ci;
        }
        for (i = 0;i <= 5;i++)
            for (j = 0;j <= 5;j++)
                for (k = 0;k <= 5;k++)
                    for (l = 0;l <= 5;l++)
                        for (m = 0;m <= 5;m++)
                            f[i][j][k][l][m] = 10000000;
        f[0][0][0][0][0] = 0; 
        for (z = 1;z <= n;z++)
            for (i = a[z].k[1];i <= x[1];i++)
                for (j = a[z].k[2];j <= x[2];j++)
                    for (k = a[z].k[3];k <= x[3];k++)
                        for (l = a[z].k[4];l <= x[4];l++)
                            for (m = a[z].k[5];m <= x[5];m++)
                                f[i][j][k][l][m] = min(f[i][j][k][l][m],f[i - a[z].k[1]][j - a[z].k[2]][k - a[z].k[3]][l - a[z].k[4]][m - a[z].k[5]]+ a[z].p);
        printf("%d
    ", f[x[1]][x[2]][x[3]][x[4]][x[5]]);
        return 0;
    }
  • 相关阅读:
    JAVA中拼音工具类
    USB接口不同颜色的作用
    java的反射机制使用方法
    利用FrameLayout+LinearLayout实现Android底部导航栏切换
    Andorid中如何读取文件
    JAVA中解压压缩包到制定文件夹工具方法
    Andorid中子线程更新主线程方法
    委托的定义使用
    Json的序列化和反序列化
    在线支付(模拟支付宝)
  • 原文地址:https://www.cnblogs.com/zbtrs/p/5962765.html
Copyright © 2011-2022 走看看