BZOJ 2260: 商店购物/BZOJ 4349: 最小树形图 朱刘算法

2260: 商店购物

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 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)行由一个实数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

朱刘算法流程

  1. 找出除根节点外每个点的最小入边,置入边集 E,记为 mn[]
  2. 判断原图在只通过边集 E 下是否有除根节点以外的独立点,若有,算法无解
  3. 判断是否有环,若无,则得到的边集 E 即原图的最小树形图,贪心的证明是显然的...
  4. 若有环,则记录环的编号后对环进行缩点,对于环之间的边,重建方式为:对于环中点 x,若有边 x->i val 则连接 new->i val,若有边 i->x val 则连接 i->new val-mn[x]
  5. 置新点数为环数,继续循环


转自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
*/


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值