天上掉Pizza
时间限制: 3 Sec 内存限制: 128 MB提交: 73 解决: 48
[提交][状态][讨论版]
题目描述
明明喜欢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为编号为i的Pizza的价格,ai为编号为i的Pizza的面积,ni为购买i号Pizza能得到ni张优惠券
接下来ni*2个数,分别表示该张优惠券对xi号Pizza打折(1<=xj<=m,i<>xj),折扣为yj(1<=yj<=50)
输入以m=0结束。
输出
输出购买m个Pizza中某一些的最低单位面积价格。保留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可以不全部购买
一眼看下去也许没什么思路,阅读量有些大,还好输出那里有些提示,看m的范围,也就是披萨总数可以发现,可以将披萨压缩,
表示为已经买了哪几个披萨,因此dp[x]表示买了x状态的披萨的最小那个什么。。
和导游2还是有些类似的,但这里需要预处理出买了第几个披萨对其他披萨的优惠,这样一个数组,然后和导游2的转移差不多类似。
#include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> #include<string> using namespace std; const int MAXN=17; struct fzy { double s,fee,ave; void init() { s=fee=ave=-1; } }dp[(1<<16)+1]; double g[MAXN][MAXN]; int a[MAXN],p[MAXN]; int n,num; void init() { for (int i=0;i<MAXN;i++) for (int j=0;j<MAXN;j++) g[i][j]=1; for (int i=0;i<=(1<<16);i++) dp[i].init(); } void dfs(int sta,int num) { if (num==0) { dp[sta].s=0; dp[sta].fee=0; dp[sta].ave=0; return; } if (dp[sta].fee>0) return; double rs,rf,ra=1<<MAXN; int xx; for (int i=0;i<n;i++) { if ((1<<i)&sta) { xx=sta^(1<<i); dfs(xx,num-1); double x=p[i+1]*1.0; for (int ii=0;ii<n;ii++) if ((1<<ii)&xx) { x*=g[ii+1][i+1]; } x+=dp[xx].fee; if (x<ra) ra=x; } } dp[sta].fee=ra; } double min(double a,double b) { return a>b?b:a; } int main() { while (scanf("%d",&n)&&n) { init(); int num,x,y; for (int i=1;i<=n;i++) { scanf("%d%d%d",&p[i],&a[i],&num); for (int j=1;j<=num;j++) { scanf("%d%d",&x,&y); g[i][x]=(1-y*1.0/100); } } dfs((1<<n)-1,n); double ans=1<<MAXN; for (int i=1;i<=(1<<n);i++) { dp[i].s=0; for (int j=0;j<n;j++) if (i&(1<<j)) dp[i].s+=a[j+1]; dp[i].ave=dp[i].fee/dp[i].s; } for (int i=1;i<(1<<n);i++) ans=min(ans,dp[i].ave); printf("%.4f ",ans); } }