洛谷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\n", 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\n", 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\n", need[j], a[i].num[need[j]]);
        printf("钱%d\n", a[i].money);
    }
    for (int i = 1; i <= t; i++)
        printf("%d %d %d\n", need[i], neednum[need[i]], needmoney[need[i]]);
        */
    dfs(0,t);
    printf("%d\n", 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\n", f[x[1]][x[2]][x[3]][x[4]][x[5]]);
    return 0;
}
时间: 2024-10-12 21:55:01

洛谷P2732 商店购物 Shopping Offers的相关文章

商店购物 (shopping.c/cpp/pas)

1.商店购物 (shopping.c/cpp/pas) 在滨海市开着 n 家商店,编号依次为 1 到 n,其中编号为 1 到 m 的商店有日消费量上 限,第 i 家商店的日消费量上限为 wi. 海霸王每次购物的过程是这样的:依次经过每家商店,然后购买非负整数价格的商品,并 在结账的时候在账本上写上在这家商店消费了多少钱.当然,他在这家商店也可以什么都不 买,然后在账本上写上一个 “0”. 这一天,海霸王日常完成了一次购物,但是他不慎遗失了他的账本.他只记得自己这一 天一共消费了多少钱,请写一个程

洛谷P1450 [HAOI2008]硬币购物 动态规划 + 容斥原理

洛谷P1450 [HAOI2008]硬币购物 动态规划 + 容斥原理 1.首先我们去掉限制 假设 能够取 无数次 也就是说一开始把他当做完全背包来考虑 离线DP 预处理 复杂度 4*v 用f[ i ] 表示 空间 为 i 的方案数 答案ans 其实就是所有方案 - 所有超过限制的方案 限制指的就是题目中限制 某个硬币有几枚 然后所有超过限制的方案用容斥来做 所有超过限制的方案 要减 == -1 超过限制的方案 - 2 超过限制的方案 - 3 超过限制的方案 - 4 超过限制的方案 + 1和2 超

Shopping Offers

Shopping Offers 在商店中,每一种商品都有一个价格(用整数表示).例如,一朵花的价格是 2 zorkmids (z),而一个花瓶的价格是 5z .为了吸引更多的顾客,商店举行了促销活动. 促销活动把一个或多个商品组合起来降价销售,例如: 三朵花的价格是 5z 而不是 6z, 两个花瓶和一朵花的价格是 10z 而不是 12z. 编写一个程序,计算顾客购买一定商品的花费,尽量利用优惠使花费最少.尽管有时候添加其他商品可以获得更少的花费,但是你不能这么做. 对于上面的商品信息,购买三朵花

洛谷1455 搭配购买(并查集)

洛谷1455 搭配购买 本题地址:http://www.luogu.org/problem/show?pid=1455 题目描述 明天就是母亲节了,电脑组的小朋友们在忙碌的课业之余挖空心思想着该送什么礼物来表达自己的心意呢?听说在某个网站上有卖云朵的,小朋友们决定一同前往去看看这种神奇的商品,这个店里有n朵云,云朵已经被老板编号为1,2,3,……,n,并且每朵云都有一个价值,但是商店的老板是个很奇怪的人,他会告诉你一些云朵要搭配起来买才卖,也就是说买一朵云则与这朵云有搭配的云都要买,电脑组的你觉

【洛谷八连测R7】nzhtl1477-我回来了

[洛谷八连测R7]nzhtl1477-我回来了 题目描述 68号岛有n个商店,有的商店直接有小路连接,小路的长度都为1,格里克告诉了你哪些地方可能有做黄油蛋糕的原料. 但是那个人是个坑货,所以他会告诉你一些商店,然后告诉你距离这些商店距离 <= k的商店中都是可能有原料的. 然后你要把这些可能的商店每个都去一遍,你想知道你要去多少个商店. 由于你是勇者,所以有m次询问 简洁题意: 给你一个图,每次查询的时候给一堆特殊点以及一个数k,求图中有多少点距离至少一个特殊点距离不超过k,边是无向的. 输入

洛谷 P2709 BZOJ 3781 小B的询问

题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. 输入输出格式 输入格式: 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. 输出格式: M行,每行一个整数,其中第i行的整数表示第i个询问的答案. 输入输出样例 输入样例#1: 6 4 3 1 3 2 1 1 3

洛谷1231 教辅的组成

洛谷1231 教辅的组成 https://www.luogu.org/problem/show?pid=1231 题目背景 滚粗了的HansBug在收拾旧语文书,然而他发现了什么奇妙的东西. 题目描述 蒟蒻HansBug在一本语文书里面发现了一本答案,然而他却明明记得这书应该还包含一份练习题.然而出现在他眼前的书多得数不胜数,其中有书,有答案,有练习册.已知一个完整的书册均应该包含且仅包含一本书.一本练习册和一份答案,然而现在全都乱做了一团.许多书上面的字迹都已经模糊了,然而HansBug还是可

洛谷教主花园dp

洛谷-教主的花园-动态规划 题目描述 教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会因为不适合这个位置的土壤而损失观赏价值. 教主最喜欢3种树,这3种树的高度分别为10,20,30.教主希望这一圈树种得有层次感,所以任何一个位置的树要比它相邻的两棵树的高度都高或者都低,并且在此条件下,教主想要你设计出一套方案,使得观赏价值之和最高. 输入输出格式 输入格式: 输入文件garden.in的第1行为一个正整数n,表示需要种的

洛谷 P2801 教主的魔法 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=2801 题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. 每个人的身高一开始都是不超过1000的正整数.教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W.(虽然L=R时并不