天上掉Pizza

C: 天上掉Pizza

时间限制: 3 Sec  内存限制: 128 MB

题目描述

明明喜欢Pizza,但总是缺钱。有一天,他在报纸上阅读,他最喜爱的比萨饼店��必胜客,正在对大批新Pizza运行的促销。促销的办法是:在购买一些Pizza后,可能得到一些优惠券,可以对另一些Pizza进行打折,更令人惊喜的是这些优惠券可以结合起来。但是,有一个限制,Pizza必须一个接一个买,而后得到的优惠券也不可能追溯前面已经买过的Pizza。明明想尝试若干新品Pizza,可又没有充足的钱,为了能省一些,明明费劲脑力,就请你帮他计算一下如何购买Pizza,使得其平均价格最低!平均价格是指买到Pizza的总价格/总面积,即单位面积的Pizza的价格。还要注意,“安排顺序”只要求按照给定的顺序安排每个操作。不一定是各机器上的实际操作顺序。在具体实施时,有可能排在后面的某个操作比前面的某个操作先完成。

输入

有多组输入数据。

每组输入数据第一行为m(1<=m<=15).

接下来m行,每行前3个数pi,ai,ni(1<=pi<=10000,1<=ai<=10000,0<=nipi为编号为iPizza的价格,ai为编号为iPizza的面积,ni为购买iPizza能得到ni张优惠券

接下来ni*2个数,分别表示该张优惠券对xiPizza打折(1<=xj<=m,i<>xj),折扣为yj(1<=yj<=50)

输入以m=0结束。

 

输出

输出购买mPizza中某一些的最低单位面积价格。保留4位小数。

(如果一个Pizza原价10,得到了一张50和一张20的优惠券,那么购买它实际所需的价值就是10*0.5*0.8=4)

 

样例输入

1

80 30 0

2

200 100 1 2 50

200 100 0

5

100 100 2 3 50 2 50

100 100 1 4 50

100 100 1 2 40

600 600 1 5 10

1000 10 1 1 50

0

样例输出

2.6667

1.5000

0.5333

提示

Pizza可以不全部购买

 

Solution

注意到优惠券使用的对象是确定的,考虑状压

F[i]表示当购买的Pizzai的二进制位表示的数中的那些“1”时的最小价格,可以的决策的个数显然是i1的个数,

枚举这iPizza中最后一个买的是j

F[i]=min{f[i-(1<<j-1)]+price[j]}

最后计算单位价格的时候在枚举一遍F数组除以面积就可以了

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;

const int MAXN=16,MAXS=1<<15;
double f[MAXS],ans;
int p[MAXN],s[MAXN],size[MAXS],c[MAXN][MAXN];
int n,m,x,y;

int main()
{
	while (scanf("%d",&n) && n)
	{
		memset(size,0,sizeof(size));
		memset(c,0,sizeof(c));
		f[0]=0; ans=1000000000;
		for (int i=1;i<=n;i++)
		{
			scanf("%d%d%d",&p[i],&s[i],&m);
			for (int j=1;j<=m;j++)
			{
				scanf("%d%d",&x,&y);
				c[i][x]=y;
			}
		}
		for (int i=1;i<=(1<<n)-1;i++)
		{
			f[i]=1000000000;
			for (int j=1;j<=n;j++)
				if (i&(1<<j-1))
				{
					double w=p[j];
					for (int k=1;k<=n;k++)
						if (k!=j && (i&(1<<k-1))) w=w*(100-c[k][j])/100;
					f[i]=min(f[i],f[i-(1<<j-1)]+w); 
					int t=c[0][0];
					size[i]=size[i-(1<<j-1)]+s[j];
				}
			if (ans>f[i]/size[i]) ans=f[i]/size[i];
		}
		printf("%.4f\n",ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值