【LuoguP2792 】[JSOI2008]小店购物(最小树形图)

题目链接

题目描述

小店的优惠方案十分简单有趣:

一次消费过程中,如您在本店购买了精制油的话,您购买香皂时就可以享受2.00元/块的优惠价;如果您在本店购买了香皂的话,您购买可乐时就可以享受1.50元/听的优惠价......诸如此类的优惠方案可概括为:如果您在本店购买了商品A的话,您就可以以P元/件的优惠价格购买商品B(购买的数量不限)。

有趣的是,你需要购买同样一些商品,由于不同的买卖顺序,老板可能会叫你付不同数量的钱。比如你需要一块香皂(原价2.50元)、一瓶精制油(原价10.00元)、一听可乐(原价1.80元),如果你按照可乐、精制油、香皂这样的顺序购买的话,老板会问你要13.80元;而如果你按照精制油、香皂、可乐这样的顺序购买的话,您只需付13.50元。

该处居民发现JSOI集训队的队员均擅长电脑程序设计,于是他们请集训队的队员编写一个程序:在告诉你该小店商品的原价,所有优惠方案及所需的商品后,计算至少需要花多少钱(不允许购买任何不必要的商品,即使这样做可能使花的钱更少)。

Sol

首先不用买的全部丢掉 , 优惠活动也不用管。
考虑一个最优策略 , 显然我们不会蠢到白白的优惠不要 , 那么一定是先所有要买的物品都买一个 , 然后就能取得所有优惠。直接取最小值当做价格即可。

那么问题就是让所有物品买一次后总价格最小。
这就很像一个生成树了。
由于有些物品可能没有优惠 , 我们建立一个超级点 , 向所有其他物品连原价的边 , 相当于买了超级点其他物品都能以原价的优惠购买。
这样就是要求一个以超级点为根的最小树形图了 , 朱刘算法即可。

简单说明朱刘算法的求解步骤:

首先要明确的一点是每一个点只会有一条入边。

  1. 为所有点找到一个最小的入边。
  2. 把这些边的权值加入答案 , 然后判断图中是否存在环。
  3. 不存在环那么算法结束 , 否则缩环(直接往入边方向跳即可,不要tarjan) , 并把所有不在环内边的边的权值减去指向点的最小入边(之前的环不合法 , 其中要去掉一条边 , 这里减去原入边边权就是在之后选择新的边的时候考虑了这个权值的变化)

本题code:

#include<bits/stdc++.h>
using namespace std;
typedef double db;
const int M=6000;
const int N=51;
struct edge{
    int u,v;db val;
    edge(){u=v=0,val=0.0;}
    edge(int a,int b,db c){u=a,v=b,val=c;}
}a[M],b[M];
int In[N],vis[N],bel[N],cnt=0,m,n,bcc;
db cost[N];int ned[N];
db Mi[N];
int rt;db ans=0;
int flag=0;
bool MST(){
    for(int i=1;i<=n;++i) In[i]=vis[i]=bel[i]=0;bcc=0,cnt=0;
    for(int i=1;i<=m;++i) {
        int u=a[i].u,v=a[i].v;db w=a[i].val;
        if(!In[v]||a[In[v]].val>w) In[v]=i;
    }
    for(int i=flag;i<=n;++i) {
        if(!flag&&!ned[i]) continue;
        if(i!=rt) ans+=a[In[i]].val;
        if(vis[i]) continue;
        int u=i;
        for(;u^rt&&vis[u]!=i&&!bel[u];u=a[In[u]].u) vis[u]=i;
        if(u^rt&&!bel[u]) {
            ++bcc;while(bel[u]!=bcc) bel[u]=bcc,u=a[In[u]].u;
        }
    }
    if(!bcc) return 0;
    for(int i=flag;i<=n;++i) {
        if(!flag&&!ned[i]&&i!=rt) continue;
        if(!bel[i]) bel[i]=++bcc;
    }
    for(int i=1;i<=m;++i) {
        int u=a[i].u,v=a[i].v;db w=a[i].val;
        if(bel[u]==bel[v]) continue;
        db goi=a[In[v]].val;b[++cnt]=(edge){bel[u],bel[v],w-goi};
    }
    for(int i=1;i<=cnt;++i) a[i]=b[i];
    n=bcc;m=cnt;
    return 1;
}
int main()
{
    cin>>n;int tot=n;// !! 注意记录啊
    for(int i=1;i<=n;++i) cin>>cost[i]>>ned[i],Mi[i]=cost[i];
    cin>>m;
    for(int i=1;i<=m;++i) {
        int A,B;db P;
        cin>>A>>B>>P;
        if(!ned[A]||!ned[B]) --i,--m;
        else {Mi[B]=min(Mi[B],P);a[i]=edge(A,B,P);}
    }
    for(int i=1;i<=n;++i) if(ned[i]) a[++m]=edge(0,i,cost[i]);
    rt=0;flag=0;
    while(MST()) rt=bel[rt],flag=1;
    for(int i=1;i<=tot;++i) {
        if(ned[i]) {
            --ned[i];
            ans+=Mi[i]*(db)ned[i];
        }
    }
    printf("%.2lf\n",ans);
}

原文地址:https://www.cnblogs.com/NeosKnight/p/10440529.html

时间: 2024-10-12 08:23:48

【LuoguP2792 】[JSOI2008]小店购物(最小树形图)的相关文章

Luogu2792 JSOI2008 小店购物 最小树形图

传送门 被题意杀 本以为一个种类的物品一定要一起买 看了题解才知道可以先把所有要买的物品买一个,剩下要买的物品就可以得到这个种类的物品能够得到的最大优惠-- 所以现在只需要知道:第一次买所有物品一遍时按照什么顺序买最优惠 建一个超级源点向每一个物品连权值等同于其价值的边,对于优惠\((A,B,P)\)从\(A\)向\(B\)连权值为\(P\)的遍,然后一遍最小树形图即可. 注意一个购买数量为\(0\)的点和它的所有出入边都要被忽视 #include<bits/stdc++.h> //This

LUOGU 2792: [JSOI2008]小店购物 最小树形图

title LUOGU 2792 简化题意: 若干件物品,每个物品有一个原价,购买某件物品后可以以更优价购买另一件物品.每件物品有一个需求数目,既不能多买,也不能少买(如果需求 0 件就不能买,哪怕可能使得总价最优). analysis 这题有一个很棒的贪心算法,对于某件物品,我们怎样使得购买它的代价最小呢? 我们可以贪心的在这件物品所有的可行方案(原价与优惠价)里面取最小的,做一次乘法运算即可得出答案. 关键是,怎样使得这个贪心是正确的呢?我们发现,假如所有物品都被购买了的话,那么就可以保证这

题解 P2792 【[JSOI2008]小店购物】

题目链接 Solution [JSOI2008]小店购物 题目大意:有若干件物品,每个物品有一个原价,购买某件物品后可以以更优价购买另一件物品.每件物品有一个需求数目,既不能多买,也不能少买(如果需求\(0\)件你就不能买,哪怕可能使得总价最优) 题目分析:看到题解区巨佬的题解,发现此题有一个绝妙的贪心做法. 对于某件物品,我们怎样使得购买它的代价最小呢?我们可以贪心的在这件物品所有的可行方案(原价与优惠价)里面取最小的,做一次乘法运算即可得出答案 关键是,怎样使得这个贪心是正确的呢?我们发现,

JSOI2008 小店购物

https://www.luogu.org/problem/show?pid=2792 题目背景 JSOI集训队的队员发现,在他们经常活动的集训地,有一个小店因为其丰富的经营优惠方案深受附近居民的青睐,生意红火. 题目描述 小店的优惠方案十分简单有趣: 一次消费过程中,如您在本店购买了精制油的话,您购买香皂时就可以享受2.00元/块的优惠价:如果您在本店购买了香皂的话,您购买可乐时就可以享受1.50元/听的优惠价......诸如此类的优惠方案可概括为:如果您在本店购买了商品A的话,您就可以以P元

bzoj2260: 商店购物 &amp;&amp; 4349: 最小树形图

Description Grant是一个个体户老板,他经营的小店因为其丰富的优惠方案深受附近居民的青睐,生意红火.小店的优惠方案十分简单有趣.Grant规定:在一次消费过程中,如果您在本店购买了精制油的话,您购买香皂时就可以享受2.00元/块的优惠价:如果您在本店购买了香皂的话,您购买可乐时就可以享受1.50元/听的优惠价……诸如此类的优惠方案就是说:如果您在本店购买了商品A的话,您就可以以P元/件的优惠价格购买商品B(购买的数量不限).有趣的是,你需要购买同样一些商品,由于不同的购买顺序,Gr

bzoj2260: 商店购物&amp;&amp;4349: 最小树形图

最小树形图问题啊 最小树形图是撒哩,就是给你一个有向图,确定一个根,要你到达所有点,那棵最短路径树的总边权 做这个用的是朱(jv)刘(lao)算法. 首先假如有多个联通块就无解啦 对应每个点(除了根),找到一条连向它的最短的边,假如没有环,那这个就是答案嘛 否则就找环,然后缩点,对于一个环,假如要从它的一个成员节点x断开,那么答案是减去环上的边,然后加上连进来的边,那么我们就把所有连向x的边的权,减去环上这条边的权(感觉很像数据备份退流的思想) 不断重复直到没有环. #include<cstdi

HDU2121 Ice_cream’s world II【最小树形图】【不定根】

Ice_cream's world II Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3005    Accepted Submission(s): 704 Problem Description After awarded lands to ACMers, the queen want to choose a city be he

前有淘宝后有“微信小店” 京东怎么玩拍拍?

浓缩观点 就在京东沉醉在微信开放了一级入口的时候,腾讯悄然上线了微信小店,这个无厘头的开幕,让准备在微信搭台唱戏的京东,顿时冷了下场. 我认为京东上市以来,干的最漂亮的一件事就是"重启"了拍拍网,即完成了腾讯交付的"政治任务",又很好地提升了股价,还顺带恶心了把淘宝,一箭三雕. 不过,好戏没玩,就在京东沉醉在微信开放了一级入口的时候,腾讯今天悄然上线了微信小店,这个无厘头的开幕,让准备在微信搭台唱戏的京东,顿时冷了下场. 且不说,微信小店能做成什么样,但是腾讯内部已

POJ--3164--Command Network【朱刘算法】最小树形图

链接:http://poj.org/problem?id=3164 题意:告诉n个点坐标,m条边表示两个点之间有路.从1点開始建立一个有向图最小生成树. 朱刘算法模板题 ========================== 切割线之下摘自user_id=Sasuke_SCUT" style="color:rgb(202,0,0); text-decoration:none; font-family:Arial; font-size:14px; line-height:26px"