2260: 商店购物
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 280 Solved: 94
[Submit][Status][Discuss]
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
朱刘算法流程
- 找出除根节点外每个点的最小入边,置入边集 E,记为 mn[]
- 判断原图在只通过边集 E 下是否有除根节点以外的独立点,若有,算法无解
- 判断是否有环,若无,则得到的边集 E 即原图的最小树形图,贪心的证明是显然的...
- 若有环,则记录环的编号后对环进行缩点,对于环之间的边,重建方式为:对于环中点 x,若有边 x->i val 则连接 new->i val,若有边 i->x val 则连接 i->new val-mn[x]
- 置新点数为环数,继续循环
转自Z基的blogBZOJ 2260 商店购物/BZOJ 4349 最小树形图
#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<complex>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;
typedef double db;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int inf=0X3f3f3f3f;
const int N=1010;
const int M=10100;
int n,m,ecnt,b[N],last[N],pos[N],pre[N],id[N],vis[N];
db mn[N],a[N];
struct EDGE{int fr,to,nt;db val;}e[M];
inline void add(int u,int v,db val)
{e[++ecnt]=(EDGE){u,v,last[u],val};last[u]=ecnt;}
db zhuliu()
{
int root=1;db ret=0;
while(1)
{
memset(pre,0,sizeof(pre));
for(int i=1;i<=n;i++)mn[i]=inf;
for(int i=1;i<=m;i++)
if(e[i].to!=e[i].fr&&e[i].val<mn[e[i].to])
{mn[e[i].to]=e[i].val;pre[e[i].to]=e[i].fr;}
int tot=0;mn[root]=0;
for(int i=1;i<=n;i++)if(mn[i]>=inf)return -1;
memset(id,0,sizeof(id));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
int v=i;ret+=mn[i];
while(vis[v]!=i&&!id[v]&&v!=root)
{vis[v]=i;v=pre[v];}
if(v!=root&&!id[v])
{id[v]=++tot;for(int u=pre[v];v!=u;u=pre[u])id[u]=tot;}
}
if(tot==0)break;
for(int i=1;i<=n;i++)if(!id[i])id[i]=++tot;
for(int i=1,v;i<=m;i++)
{
v=e[i].to;
e[i].to=id[e[i].to];
e[i].fr=id[e[i].fr];
if(e[i].to!=e[i].fr)
e[i].val-=mn[v];
}
root=id[root];n=tot;
}
return ret;
}
int main()
{
n=read();int cnt=1;db val;
for(int i=1,u;i<=n;i++)
{
scanf("%lf",&val);u=read();
if(u)
{
pos[i]=++cnt;a[cnt]=val;b[cnt]=u-1;
add(1,cnt,val);
}
}
n=cnt;int k=read();
for(int i=1,u,v;i<=k;i++)
{
u=read();v=read();scanf("%lf",&val);
if(!pos[u]||!pos[v])continue;
add(pos[u],pos[v],val);
a[pos[v]]=min(a[pos[v]],val);
}
m=ecnt;db ans=0;
for(int i=2;i<=n;i++)ans+=a[i]*b[i];
printf("%.2lf\n",ans+zhuliu());
return 0;
}
/*
4
10.00 1
1.80 1
3.00 0
2.50 2
2
1 4 2.00
4 2 1.50
15.50
*/