题意:
要在一天内销售不超过N把魔法剑,并给出一些事件:每个事件由
Ti,Ci,Pi
T
i
,
C
i
,
P
i
这个三元组组成。
分别表示:有
Pi
P
i
的概率,有一个客人会在
Ti
T
i
时刻进店,并以
Ci
C
i
的价格购买魔法剑。
并且有如下约束条件:每个时刻最多只有一个人可能会进店,可能有客人一天内在多个时间存在进店的可能性,但最多只进店一次。每个客人最多只买一把剑,并且你可以选择是否卖给他。现在求在最大化收益的期望值的方案下,这个最大期望值的值。
0≤Ti≤23
0
≤
T
i
≤
23
分析:
题目看起来很复杂,但理一理其实很简单:
有多个可能收益的事件,每个事件都有特定的收益和可能性,DP状态的定义非常简单:
DP[i][j]表示剩余i个时间,剩余j把剑的最大期望收益。
由于一个特殊的约束:一个客人不会进店多次,这也就造成了我们不能将“一个人多次进店”看作“不同的人进店”,换句话说,我们必须考虑对于某一个特定的人的影响。因此,再结合输入数据的范围,我们可以利用状态压缩,来保存每个不同的人的影响。由于人的数量不超过24,如果直接状态压缩,数据量为
224=16777216
2
24
=
16777216
,结合前两维,很显然会超时。所以我们再来看看需要状压的本质:为了解决一个人到达多次的情况。所以我们只需要针对于这类人状压即可,也就是说,我们只针对多次访问的人状压。这样一来,最多只有12个人有多次可能会到达,所以复杂度就是
212=4096
2
12
=
4096
,复杂度也就降下来了。
下面再说说具体转移:
在此之前,再重申一下状态定义
DP[i][j][s]表示第i个时间之后,还剩下j把剑,目前多次来的客人来的状态为s的情况下的最大期望值。
那么转移即为,若当前的客人可以来多次,那么
DP[i][j][s]
D
P
[
i
]
[
j
]
[
s
]
=(1−pos)∗DP[i+1][j][s]
=
(
1
−
p
o
s
)
∗
D
P
[
i
+
1
]
[
j
]
[
s
]
//客人没来的概率,其中pos表示客人在当前时刻到来的概率,不等同于题目给出的那个值,需要处理
+pos∗max(DP[i+1][j−1][s|s1]+val,DP[i+1][j][s|s1])
+
p
o
s
∗
m
a
x
(
D
P
[
i
+
1
]
[
j
−
1
]
[
s
|
s
1
]
+
v
a
l
,
D
P
[
i
+
1
]
[
j
]
[
s
|
s
1
]
)
//s1表示当前客人在二进制下的状态。
初始状态很显然:
任意一个i=24的状态均为0(这一天已经结束,没有期望值)
目标状态为DP[0][n][0]
注:这个代码交在vjudge上显示0分,在topcoder的客户端上和标程拿一样的分,并且经过本地测试无误。(估计是vjudge一个神奇的bug)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<iostream>
#define SF scanf
#define PF printf
#define MAXN 55
#define MAXT 30
#define MAXM 5000
#define EPS 1e-6
using namespace std;
string read;
int las;
char Read(int &x){
x=0;
char c;
while(c=read[las++],las!=read.size()&&(c<'0'||c>'9'));
x=c-'0';
if(las==read.size())
return 0;
while(c=read[las++],las!=read.size()&&c>='0'&&c<='9')
x=x*10+c-'0';
if(las==read.size())
return 0;
return c;
}
struct node{
int t;
double val,pos;
node () {}
node (int t1,double val1,double pos1):t(t1),val(val1),pos(pos1) {}
};
int n,cnt;
vector<node>a[MAXN];
node time1[MAXT];
int r2[MAXM];
int used[MAXN],id[MAXN];
double dp[MAXT][MAXT][MAXM];
bool vis[MAXT][MAXT][MAXM];
double solve(int t,int sw,int s){
if(t==24||sw==0)
return 0;
if(vis[t][sw][s]!=0)
return dp[t][sw][s];
vis[t][sw][s]=1;
int x=time1[t].t;
if(x==-1){
dp[t][sw][s]=solve(t+1,sw,s);
return dp[t][sw][s];
}
int s1;
if(used[x]==1)
s1=(1<<id[x]);
else
s1=0;
if(s1&s){
dp[t][sw][s]=solve(t+1,sw,s);
return dp[t][sw][s];
}
double res1=(1-time1[t].pos)*solve(t+1,sw,s);
res1+=time1[t].pos*max(time1[t].val+solve(t+1,sw-1,s|s1),solve(t+1,sw,s|s1));
dp[t][sw][s]=res1;
return res1;
}
class NewItemShop{
public:
double getMaximum(int n1,vector<string> r1){
n=n1;
for(int i=0;i<r1.size();i++)
read+=r1[i]+"|";
int x;
for(int i=0;;i++){
char c=Read(x);
r2[++cnt]=x;
if(c==0)
break;
if(c=='|')
r2[++cnt]=-1;
}
r2[++cnt]=-1;
/*for(int i=1;i<=cnt;i++)
PF("%d ",r2[i]);
PF("|");*/
int sum=0;
for(int i=1;i<=cnt;i++){
if(r2[i]==-1)
sum++;
else{
a[sum].push_back(node(r2[i],double(r2[i+1]),double(r2[i+2]/100.0)));
i+=2;
}
}
/*for(int i=0;i<sum;i++){
for(int j=0;j<a[i].size();j++)
PF("\n{%d %lf %lf}",a[i][j].t,a[i][j].val,a[i][j].pos);
PF("\n---------------\n");
}*/
cnt=0;
for(int i=0;i<24;i++)
time1[i].t=-1;
for(int i=0;i<sum;i++){
if(a[i].size()>1){
used[i]=1;
id[i]=cnt;
cnt++;
}
double p1=1;
for(int j=0;j<a[i].size();j++){
double p2=a[i][j].pos/p1;
p1-=a[i][j].pos;
time1[a[i][j].t]=node(i,a[i][j].val,p2);
}
}
//PF("%lf",solve(0,n,0));
return solve(0,n,0);
}
};