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

Description

Grant是一个个体户老板,他经营的小店因为其丰富的优惠方案深受附近居民的青睐,生意红火。小店的优惠方案十分简单有趣。Grant规定:在一次消费过程中,如果您在本店购买了精制油的话,您购买香皂时就可以享受2.00元/块的优惠价;如果您在本店购买了香皂的话,您购买可乐时就可以享受1.50元/听的优惠价……诸如此类的优惠方案就是说:如果您在本店购买了商品A的话,您就可以以P元/件的优惠价格购买商品B(购买的数量不限)。有趣的是,你需要购买同样一些商品,由于不同的购买顺序,Grant老板可能会叫你付不同数量的钱。比如你需要一块香皂(原价2.50元)、一瓶精制油(原价10.00元)、一听可乐(原价1.80元),如果你按照可乐,精制油,香皂这样的顺序购买的话,Grant老板会问你要13.80元;而如果你按照精制油,香皂,可乐这样的顺序购买的话,您只需付13.50元。 
现在该村的居民请你编写一个程序,告诉你Grant小店商品的原价,所有优惠方案及所需的商品,计算至少需要花多少钱。不允许购买任何不需要的商品,即使这样做可能使花得钱更少。

Input

,第一行为一个整数n(1<=n<=50),表示Grant小店的商品种数。接下来是n行,其中第(i+1)行由一个实数C(0<Ci<=1000)和一个整数M(0<=Mi<=100)组成,其间由一个空格分隔,分别表示第i种商品的原价和所需数量。第(n+2)行又是一个整数k,表示Grant小店的优惠方案总数。接着k行,每行有二个整数A,B(1<=A,B<=n)和一个实数P(0<=P<1000),表示一种优惠方案,即如果您购买了商品A,您就可以以P元/件的优惠价格购买商品B,P小于商品B的原价。所有优惠方案的(A,B)都是不同的。为了方便,Grant不收分币,所以所有价格都不会出现分。

Output

只有一个实数,表示最少需要花多少钱。输出实数须保留两位小数。

Sample Input

4
10.00 1
1.80 1
3.00 0
2.50 2
2
1 4 2.00
4 2 1.50

Sample Output

15.50

题解:

先要了解一下什么是最小树形图

http://blog.csdn.net/wsniyufang/article/details/6747392

然后由于所有要买的东西都最少有一个,所以对于每一种东西他除了第一件以外肯定可以用最低的价格买剩下的

然后对于第一个如何来买,我们这样构图

先加一个额外的点,它向每种东西连一条权值为原价的有向边

然后对于一个优惠关系(a,b),我们从a向b连一条权值为优惠价的有向边

然后作一遍最小树形图即可

code:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 #define maxn 105
 7 #define maxm 5105
 8 using namespace std;
 9 int n,m,a,b,tim[maxn],sum[maxn],flag[maxn];
10 double c,ans;
11 int tmp,best[maxn],bel[maxn],idx,vis[maxn];
12 struct Graph{
13     int tot,now[maxn],fa[maxm],son[maxm],pre[maxm];
14     double val[maxm];
15     void init(){tot=0;memset(now,0,sizeof(now));}
16     void put(int a,int b,double c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c,fa[tot]=a;}
17     void prepare(){
18         for (int u=0;u<=n;u++) if (!flag[u])
19             for (int p=now[u],v=son[p];p;p=pre[p],v=son[p])
20                 if (best[v]==-1||val[best[v]]>val[p]) best[v]=p;
21         memset(vis,-1,sizeof(vis));
22         tmp=n,vis[0]=0;
23         for (int i=1;i<=n;i++) if (!flag[i]&&vis[i]==-1){
24             int u,v; ++idx;
25             for (u=i;vis[u]==-1;u=fa[best[u]]) vis[u]=idx;
26             if (vis[u]<idx) continue;
27             v=u,bel[u]=++tmp,vis[v]=0;
28             for (v=fa[best[v]];vis[v]==idx;v=fa[best[v]]) vis[v]=0,bel[v]=tmp;
29         }
30     }
31 }G[2];
32 void work(){
33     for (int t=1;;t^=1){
34         for (int i=0;i<=n;i++) best[i]=-1;
35         G[t].prepare(),G[t^1].init();
36         if (tmp==n){
37             for (int i=1;i<=n;i++) if (!flag[i]) ans+=G[t].val[best[i]];
38             break;
39         }
40         for (int u=0;u<=n;u++) if (!flag[u]){
41             for (int p=G[t].now[u],v=G[t].son[p];p;p=G[t].pre[p],v=G[t].son[p]){
42                 if (bel[u]&&bel[v]&&bel[u]==bel[v]) continue;
43                 int a;
44                 if (bel[u]) a=bel[u]; else a=u;
45                 if (bel[v]) G[t^1].put(a,bel[v],G[t].val[p]-G[t].val[best[v]]);
46                 else G[t^1].put(a,v,G[t].val[p]);
47             }
48             if (bel[u]) ans+=G[t].val[best[u]],flag[u]=1;
49         }
50         n=tmp;
51     }
52     printf("%.2lf\n",ans);
53 }
54 double low[maxn];
55 int main(){
56     scanf("%d",&n);
57     for (int i=1;i<=n;i++){
58         scanf("%lf%d",&c,&tim[i]);
59         if (tim[i]) G[1].put(0,i,c),low[i]=c; else flag[i]=1;
60     }
61     scanf("%d",&m);
62     for (int i=1;i<=m;i++){
63         scanf("%d%d%lf",&a,&b,&c);
64         if (flag[a]||flag[b]) continue;
65         low[b]=min(low[b],c);
66         G[1].put(a,b,c);
67     }
68     for (int i=1;i<=n;i++) if (!flag[i]) ans+=low[i]*(tim[i]-1);
69     work();
70     return 0;
71 }
时间: 2024-11-20 23:44:46

bzoj2260: 商店购物 && 4349: 最小树形图的相关文章

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

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

BZOJ 4349: 最小树形图

Description \(n\)个节点,每个节点有一个攻击代价和需要攻击的次数. 有\(k\)个关系,攻击\(x\)后,\(y\)的攻击代价变成\(z\). Solution 朱刘算法. 这个好像就是求什么最小树形图的东东... 最小树形图跟最小生成树差不多,不过最小生成树是无向图,最小树形图是有向图,让一个节点和其他节点联通的最小代价. 这个建模也非常容易,只需要确定第一次的攻击即可,之后的一定都以最小代价攻击. 朱刘算法也很简单,步骤就是 找到每个节点的最小入边. 统计答案. 找环,缩环,

Luogu2792 JSOI2008 小店购物 最小树形图

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

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

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

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

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

bzoj4349: 最小树形图

最小树形图模板题…… 这种\(O(nm)\)的东西真的能考到么…… #include <bits/stdc++.h> #define N 60 #define INF 1000000000 using namespace std; int n, m, nn; double ai[N], an[N], ci[2][N][N], ans; int bc[N]; int ini[N], vis[N], inc[N], inl[N]; int dfn; int dfs(int t) { vis[t]

Directed_MST 最小树形图

List Directed_MST 最小树形图 List Knowledge 模板 Practice 参考资料 Knowledge 求一个图中遍历到每个点的方案中的最小边权和,显然n-1条边,即一颗树即可. 最小生成树?当然这里不是的,这里的最小树形图算法是针对有向图的. 最小树形图的第一个算法是1965年朱永津和刘振宏提出的复杂度为O(VE)的算法.简称朱刘算法. 1986年, Gabow, Galil, Spencer和Tarjan提出了一个复杂度更好的实现,其时间复杂度为O(E+VlogV

hdu2121+不定根最小树形图

算和定根最小树形图相同. 我们只需:设一个权值sumw=所有边之和+1,类似于网络流,向图中加入一个超级源点,把这个点作为虚根.虚根到其他所有点之间连上一条边,边权值为sumw. 求出的值减去sumw即为最小树形图的权值. 当然,返回-1则无解.此外,当求出的值>=2*sumw,也是无解的. 1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 struct node 5 { 6 int u,v; 7

HDOJ 2121 Ice_cream’s world II 最小树形图无根树

朱刘算法 最小树形图无根树: 建立一个虚拟的根节点,向所有节点连边,权值为其他所有边的权值和+1 在求最小树形图的时候,记录和虚拟的根相连的是哪个节点 在这题中,边是从小往大加的所以直接记录的是相连的是第几号边.... Ice_cream's world II Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3442    Accept