题目描述
明明喜欢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可以不全部购买
——————————————————
状压dp,然而……我太弱了。
状压学的不是很明白所以只能看着题解写了。
于是就把路由器遇到的问题写在了程序里。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
double dp[40000];
int p[20];
int c[20][20];
int s[20];
int size[40000];
int main(){
int m;
while(scanf("%d",&m)){
if(m==0)break;
memset(size,0,sizeof(size));
memset(dp,127,sizeof(dp));
memset(c,0,sizeof(c));
double ans=2147483640;dp[0]=0;
for(int i=1;i<=m;i++){
int n;
scanf("%d%d%d",&p[i],&s[i],&n);
for(int j=1;j<=n;j++){
int x,y;
scanf("%d%d",&x,&y);
c[i][x]=y;
}
}
for(int i=1;i<=(1<<m)-1;i++){//枚举pizza购买情况
for(int j=1;j<=m;j++){
if(i&(1<<j-1)){//枚举符合i的pizza j
double w=p[j];
for(int k=1;k<=m;k++){
if(k!=j&&(i&(1<<k-1))){//枚举符合i的pizza并且不是j的k
w=w*(100-c[k][j])/100;//购买pizza k用打折券买j
}
}
dp[i]=min(dp[i],dp[i-(1<<j-1)]+w);//dp(某情况)=dp(少j的情况)+j打完折的钱
size[i]=size[i-(1<<j-1)]+s[j];//同上的计算面积的方法
}
}
if(ans>dp[i]/size[i])ans=dp[i]/size[i];//算出单位面积钱最少的
}
printf("%.4f\n",ans);
}
return 0;
}