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)行由一个实数Ci (0<Ci<=1000)和一个整数Mi (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
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 }