天上掉Pizza

天上掉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\n",ans);    
    } 
} 

 

posted @ 2017-05-23 16:17  Kaiser-  阅读(188)  评论(0编辑  收藏  举报