Luogu2792 JSOI2008 小店购物 最小树形图

传送门



被题意杀

本以为一个种类的物品一定要一起买

看了题解才知道可以先把所有要买的物品买一个,剩下要买的物品就可以得到这个种类的物品能够得到的最大优惠……

所以现在只需要知道:第一次买所有物品一遍时按照什么顺序买最优惠

建一个超级源点向每一个物品连权值等同于其价值的边,对于优惠\((A,B,P)\)从\(A\)向\(B\)连权值为\(P\)的遍,然后一遍最小树形图即可。

注意一个购买数量为\(0\)的点和它的所有出入边都要被忽视

#include<bits/stdc++.h>
//This code is written by Itst
using namespace std;

struct Edge{
    int s , t;
    double w;
}Ed[5010];
int id[101] , vis[101] , num[101] , pre[101];
int N , M , cntEd;
double sum , pri[101] , dis[101];
bool have[101][101];

void work(int rt){
    while(1){
        memset(vis , 0x3f , sizeof(vis));
        memset(id , -1 , sizeof(id));
        fill(dis , dis + N + 1 , 5e7);
        int cnt = 0;
        for(int i = 1 ; i <= cntEd ; ++i)
            if(Ed[i].s != Ed[i].t && dis[Ed[i].t] > Ed[i].w){
                dis[Ed[i].t] = Ed[i].w;
                pre[Ed[i].t] = Ed[i].s;
            }
        for(int i = 0 ; i <= N ; ++i){
            if(i == rt)
                continue;
            sum += dis[i];
            int u = i;
            vis[i] = i;
            while(u != rt && vis[pre[u]] > i)
                vis[u = pre[u]] = i;
            if(u != rt && vis[pre[u]] == i){
                do{
                    id[u] = cnt;
                    u = pre[u];
                }while(id[u] == -1);
                ++cnt;
            }
        }
        if(!cnt)
            break;
        for(int i = 0 ; i <= N ; ++i)
            if(id[i] == -1)
                id[i] = cnt++;
        for(int i = 1 ; i <= cntEd ; ++i){
            Ed[i].w -= dis[Ed[i].t];
            Ed[i].s = id[Ed[i].s];
            Ed[i].t = id[Ed[i].t];
        }
        N = cnt - 1;
        rt = id[rt];
    }
}

signed main(){
    #ifndef ONLINE_JUDGE
    //freopen("in" , "r" , stdin);
    //freopen("out" , "w" , stdout);
    #endif
    cin >> N;
    for(int i = 1 ; i <= N ; ++i){
        cin >> pri[i] >> num[i];
        Ed[++cntEd].s = 0;
        Ed[cntEd].t = i;
        if(num[i])
            Ed[cntEd].w = pri[i];
    }
    cin >> M;
    for(int i = 1 ; i <= M ; ++i){
        int a , b;
        double c;
        cin >> a >> b >> c;
        if(num[a] && num[b]){
            Ed[++cntEd].s = a;
            Ed[cntEd].t = b;
            Ed[cntEd].w = c;
            pri[b] = min(pri[b] , c);
        }
    }
    for(int i = 1 ; i <= N ; ++i)
        if(num[i])
            sum += (num[i] - 1) * pri[i];
    work(0);
    cout << fixed << setprecision(2) << sum;
    return 0;
}

原文地址:https://www.cnblogs.com/Itst/p/10351648.html

时间: 2024-10-10 08:40:13

Luogu2792 JSOI2008 小店购物 最小树形图的相关文章

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

题目链接 题目描述 小店的优惠方案十分简单有趣: 一次消费过程中,如您在本店购买了精制油的话,您购买香皂时就可以享受2.00元/块的优惠价:如果您在本店购买了香皂的话,您购买可乐时就可以享受1.50元/听的优惠价......诸如此类的优惠方案可概括为:如果您在本店购买了商品A的话,您就可以以P元/件的优惠价格购买商品B(购买的数量不限). 有趣的是,你需要购买同样一些商品,由于不同的买卖顺序,老板可能会叫你付不同数量的钱.比如你需要一块香皂(原价2.50元).一瓶精制油(原价10.00元).一听

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"