题意:

要在一天内销售不超过N把魔法剑,并给出一些事件:每个事件由Ti,Ci,PiTi,Ci,PiT_i,C_i,P_i这个三元组组成。
分别表示:有PiPiP_i的概率,有一个客人会在TiTiT_i时刻进店,并以CiCiC_i的价格购买魔法剑。
并且有如下约束条件:每个时刻最多只有一个人可能会进店,可能有客人一天内在多个时间存在进店的可能性,但最多只进店一次。每个客人最多只买一把剑,并且你可以选择是否卖给他。现在求在最大化收益的期望值的方案下,这个最大期望值的值。
0≤Ti≤230≤Ti≤230\leq T_i\leq 23


分析:

题目看起来很复杂,但理一理其实很简单:
有多个可能收益的事件,每个事件都有特定的收益和可能性,DP状态的定义非常简单:
DP[i][j]表示剩余i个时间,剩余j把剑的最大期望收益。
由于一个特殊的约束:一个客人不会进店多次,这也就造成了我们不能将“一个人多次进店”看作“不同的人进店”,换句话说,我们必须考虑对于某一个特定的人的影响。因此,再结合输入数据的范围,我们可以利用状态压缩,来保存每个不同的人的影响。由于人的数量不超过24,如果直接状态压缩,数据量为224=16777216224=167772162^{24}=16777216,结合前两维,很显然会超时。所以我们再来看看需要状压的本质:为了解决一个人到达多次的情况。所以我们只需要针对于这类人状压即可,也就是说,我们只针对多次访问的人状压。这样一来,最多只有12个人有多次可能会到达,所以复杂度就是212=4096212=40962^{12}=4096,复杂度也就降下来了。

下面再说说具体转移:
在此之前,再重申一下状态定义
DP[i][j][s]表示第i个时间之后,还剩下j把剑,目前多次来的客人来的状态为s的情况下的最大期望值。

那么转移即为,若当前的客人可以来多次,那么
DP[i][j][s]DP[i][j][s]DP[i][j][s]
=(1−pos)∗DP[i+1][j][s]=(1−pos)∗DP[i+1][j][s]=(1-pos)*DP[i+1][j][s]//客人没来的概率,其中pos表示客人在当前时刻到来的概率,不等同于题目给出的那个值,需要处理
+pos∗max(DP[i+1][j−1][s|s1]+val,DP[i+1][j][s|s1])+pos∗max(DP[i+1][j−1][s|s1]+val,DP[i+1][j][s|s1])+pos*max(DP[i+1][j-1][s|s1]+val,DP[i+1][j][s|s1])//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]);elses1=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);}
};

【概率DP】SRM515 NewItemShop相关推荐

  1. 2018.09.01 poj3071Football(概率dp+二进制找规律)

    传送门 概率dp简单题. 设f[i][j]表示前i轮j获胜的概率. 如果j,k能够刚好在第i轮相遇,找规律可以发现j,k满足: (j−1)>>(i−1)(j−1)>>(i−1) ...

  2. Discovering Gold LightOJ - 1030[概率dp或者记忆化搜索]

    题目大意:有一个[1,n][1,n][1,n]的数轴,数轴上的每个对应位置上都有金矿,你初始位置是1,然后你每次都会投色子决定你下一步跳到哪里,如果你跳出了nnn,那么你就要重新投.问你跳到nnn的时 ...

  3. 【原创】概率DP总结 by kuangbin

    概率DP主要用于求解期望.概率等题目. 转移方程有时候比较灵活. 一般求概率是正推,求期望是逆推.通过题目可以体会到这点. 首先先推荐几篇参考的论文: <信息学竞赛中概率问题求解初探> & ...

  4. poj 3071 Football(概率dp)

    http://poj.org/problem? id=3071 大致题意:有2^n个足球队分成n组打比赛.给出一个矩阵a[][],a[i][j]表示i队赢得j队的概率.n次比赛的流程像这样France ...

  5. HDU 5001 概率DP || 记忆化搜索

    2014 ACM/ICPC Asia Regional Anshan Online 给N个点,M条边组成的图,每一步能够从一个点走到相邻任一点,概率同样,问D步后没走到过每一个点的概率 概率DP  測 ...

  6. hdu 3853 LOOPS 概率DP

    简单的概率DP入门题 代码如下: 1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 ...

  7. HDU - 4035 Maze(概率dp)

    题目链接:点击查看 题目大意:给出一个 n 个点的树,初始时位于点 1 ,每个点都会给出一个概率 k[ i ] 和一个概率 e[ i ] ,其代表的意义分别是: k[ i ] :在点 i 有 k[ i ...

  8. SDUT - 2623 The number of steps(概率dp)

    题目链接:点击查看 题目大意:给出一个 n 层的三角形,第一层有 1 个点,第二层有 2 个点,第三层有 3 个点 ... 第 n 层有 n 个点,现在规定从第一层的点向下出发: 如果左下方有点并且右 ...

  9. 牛客练习赛26B 烟花 (概率DP)

    链接:https://ac.nowcoder.com/acm/contest/180/B 来源:牛客网 烟花 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言5 ...

  10. Collecting Bugs POJ - 2096(基础概率dp+期望模板)

    题意: 有s个系统,n种bug,小明每天找出一个bug,可能是任意一个系统的,可能是任意一种bug,即是某一系统的bug概率是1/s,是某一种bug概率是1/n. 求他找到s个系统的bug,n种bug ...

最新文章

  1. 开关电源输出整流二极管
  2. myeclipse自动生成hibernate映射文件的过程
  3. 前端返回的json中文变问号
  4. adb logcat 保存_保存的logcat在Android设备上的文本文件
  5. 【PAT - 甲级1095】Cars on Campus (30分)(模拟)
  6. 利用Java调用openSMILE批量处理音频文件
  7. MYSQL单列索引和组合索引分析
  8. 【图像融合】基于matlab GUI简单+拉普拉斯金字塔算法图像融合【含Matlab源码 780期】
  9. C# 二维码生成代码
  10. 控制教程 —— 介绍篇:6.状态空间控制器设计
  11. sun存储的串口连接管理_修改SUN设备管理IP的步骤
  12. 热爱,对待人生的首要态度
  13. 魔兽UI跟随鼠标移动
  14. 记录一下大三找实习的过程
  15. 2014阿里巴巴秋季校园招聘-软件研发工程师笔试题/面试问题收集
  16. 关于分布式事务、两阶段提交、一阶段提交、Best Efforts 1PC模式和事务补偿机制的研究[转]...
  17. 满记甜品“联姻”小满茶田,老品牌寻觅翻红之道
  18. 校招面试中常见的算法题整理【长文】
  19. (每日一练c++)CC36 不同的子序列
  20. windows命令行下查看进程号

热门文章

  1. 解决微信(扫码)无法直接下载apk的问题
  2. OllyDbg插件编写
  3. 5. 机器学习基石-Why can Machine Learn?
  4. Kubernetes(简称K8s)将被带入到物联网边缘计算场景中
  5. web自动化测试01
  6. linux搭建ftps(vsftpd),java代码测试上传下载
  7. 简述BeanUtils中copyProperties
  8. jsp实现数据提交以及jsp数据保存到本地
  9. 面试蚂蚁金服(意外拿到offer)分享四面经历,从线程锁到数据库
  10. 如果配置计算机硬件设备,客户端医保定点计算机设备硬件配置要求