[BZOJ4899]:记忆的轮廓(概率DP)
题目传送门
题目描述:
3 7 2
1 4
2 5
3 6
3 7
设f[i]表示正确节点i走到n的期望步数,显然f[n]=0,我们倒着递推。
f[i]=1+1/d[i]*f[i+1]+1/d[i]*∑{g[j]+f[i]}[j是i的错误儿子]
引用:移项得f[i]=d[i]+f[i+1]+s[i]
引用:复杂度线性。
首先我们需要预处理一个a[i,j],表示存档点为i,从i开始走到正确节点j的期望步数(中间不能存档)。
显然有边界条件a[i,i]=0。对于i<j,可以列出递推式:
a[i,j]=a[i,j-1]+1+1/d[j-1]*∑{g[k]+a[i,j]}[k是j-1的错误儿子]
引用:移项得a[i,j]=a[i,j-1]*d[j-1]+d[j-1]+s[j-1]
引用:可以用n^2的时间预处理a,然后做dp就很好转移了。
枚举下一次的存档点k,那么f[i,j]可以由f[k,j-1]+a[i,k]转移而来。
引用:复杂度O(n2p)
我们来估计答案的上界。考虑一种可行方案,每n/p个正确节点就设立一次存档位置,那么答案最大是多少呢?考虑最坏情况,观察a的转移,应该每变 换一次存档点,大约需要3(n/p)*s[i]+3(n/p-1)*s[i+1]+3(n/p-2)*s[i+2]+……
引用:因为最多m个节点,s的上限是1500(实际上也远远达不到),把所有s都视为这个上限,提取公因数,计算一下那个等比数列求和,由于p是有下界的, 因此n/p有上界14,发现最后也就是个12位数的样子,那么我们估计出答案最大也不会超过这个,可以放心做了。而至于a会爆炸的问题,double是可以 存很多位的,而且太大的a肯定不可能被用上。
那么其实,针对答案不会特别大,a的增长又很恐怖,我们还可以思考对70%的算法优化。那就是设定一个常数step,每次转移最多从距当前step步远的 位置转移过来。step取40多基本不会有问题了,因为a的下界已经是2^40了,而答案的上界远远没有达到,经过精确计算还可以再把step调小一点。
引用:复杂度O(np log ans)
代码时刻:
#include<bits/stdc++.h>
using namespace std;
struct rec
{int nxt;int to;
}e[5000];
int head[5000],cnt;
int n,m,p;
double g[5000],s[5000],dp[5000];
bool vis[5000];
int du[5000];
void pre_work()//多测不清空,爆零两行泪……
{memset(head,0,sizeof(head));memset(dp,0,sizeof(dp));memset(g,0,sizeof(g));memset(s,0,sizeof(s));memset(du,0,sizeof(du));cnt=0;
}
void add(int x,int y)
{e[++cnt].nxt=head[x];e[cnt].to=y;head[x]=cnt;
}
void dfsgetG(int x)//计算g数组
{vis[x]=1;g[x]=1;for(int i=head[x];i;i=e[i].nxt){dfsgetG(e[i].to);g[x]+=g[e[i].to]*1.0/(double)du[x];}
}
int main()
{int T;scanf("%d",&T);while(T--){pre_work();scanf("%d%d%d",&n,&m,&p);for(int i=1;i<=n-1;i++)du[i]=1;//1-(n-1)中,每一个节点都要加上它到下一个正确节点的边for(int i=n+1;i<=m;i++){int a,b;scanf("%d%d",&a,&b);du[a]++;add(a,b);}for(int i=n+1;i<=m;i++){if(vis[i])continue;dfsgetG(i);}for(int i=1;i<=n;i++)for(int j=head[i];j;j=e[j].nxt)s[i]+=g[e[j].to];//计算s数组for(int i=n-1;i;i--)//倒推计算答案dp[i]=dp[i+1]+du[i]+s[i];cout<<fixed<<setprecision(4)<<dp[1]<<endl;//保留小数输出}return 0;
}
70%代码:
#include<bits/stdc++.h>
using namespace std;
struct rec
{int nxt;int to;
}e[2000];
int head[2000],cnt;
int n,m,p;
double g[2000],s[2000],dp[2000][2000],Map[2000][2000];
bool vis[2000];
int du[2000];
void pre_work()
{for(int i=0;i<=1;i++)e[i].nxt=e[i].to=0;memset(head,0,sizeof(head));memset(dp,127,sizeof(dp));memset(g,0,sizeof(g));memset(s,0,sizeof(s));memset(du,0,sizeof(du));memset(Map,0,sizeof(Map));memset(vis,0,sizeof(vis));cnt=0;
}
void add(int x,int y)
{e[++cnt].nxt=head[x];e[cnt].to=y;head[x]=cnt;
}
void dfsgetG(int x)
{vis[x]=1;g[x]=1;for(int i=head[x];i;i=e[i].nxt){dfsgetG(e[i].to);g[x]+=g[e[i].to]*1.0/(double)du[x];}
}
int main()
{int T;scanf("%d",&T);while(T--){pre_work();scanf("%d%d%d",&n,&m,&p);for(int i=1;i<=n-1;i++)du[i]=1;for(int i=n+1;i<=m;i++){int a,b;scanf("%d%d",&a,&b);du[a]++;add(a,b);}for(int i=n+1;i<=m;i++){if(vis[i])continue;dfsgetG(i);}for(int i=1;i<=n;i++)for(int j=head[i];j;j=e[j].nxt)s[i]+=g[e[j].to];for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)Map[i][j]=(Map[i][j-1]+1)*(double)du[j-1]+s[j-1];//计算a数组dp[n][1]=0;//dp初始for(int j=2;j<=p;j++)for(int i=1;i<=n;i++)for(int k=i+1;k<=n;k++)dp[i][j]=min(dp[i][j],dp[k][j-1]+Map[i][k]);cout<<fixed<<setprecision(4)<<dp[1][p]<<endl;}return 0;
}
100%算法:
#include<bits/stdc++.h>
using namespace std;
struct rec
{int nxt;int to;
}e[2000];
int head[2000],cnt;
int n,m,p;
double g[2000],s[2000],dp[2000][2000],Map[2000][2000];
bool vis[2000];
int du[2000];
void pre_work()
{for(int i=0;i<=1;i++)e[i].nxt=e[i].to=0;memset(head,0,sizeof(head));memset(dp,127,sizeof(dp));memset(g,0,sizeof(g));memset(s,0,sizeof(s));memset(du,0,sizeof(du));memset(Map,0,sizeof(Map));memset(vis,0,sizeof(vis));cnt=0;
}
void add(int x,int y)
{e[++cnt].nxt=head[x];e[cnt].to=y;head[x]=cnt;
}
void dfsgetG(int x)
{vis[x]=1;g[x]=1;for(int i=head[x];i;i=e[i].nxt){dfsgetG(e[i].to);g[x]+=g[e[i].to]*1.0/(double)du[x];}
}
int main()
{int T;scanf("%d",&T);while(T--){pre_work();scanf("%d%d%d",&n,&m,&p);for(int i=1;i<=n-1;i++)du[i]=1;for(int i=n+1;i<=m;i++){int a,b;scanf("%d%d",&a,&b);du[a]++;add(a,b);}for(int i=n+1;i<=m;i++){if(vis[i])continue;dfsgetG(i);}for(int i=1;i<=n;i++)for(int j=head[i];j;j=e[j].nxt)s[i]+=g[e[j].to];for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)Map[i][j]=(Map[i][j-1]+1)*(double)du[j-1]+s[j-1];dp[n][1]=0;for(int j=2;j<=p;j++)for(int i=1;i<=n;i++)for(int k=i+1;k<=min(n,i+12);k++)//优化上界dp[i][j]=min(dp[i][j],dp[k][j-1]+Map[i][k]);cout<<fixed<<setprecision(4)<<dp[1][p]<<endl;}return 0;
}
rp++
转载于:https://www.cnblogs.com/wzc521/p/11057553.html
[BZOJ4899]:记忆的轮廓(概率DP)相关推荐
- BZOJ4899: 记忆的轮廓 期望DP 决策单调性
题意:http://www.lydsy.com/JudgeOnline/problem.php?id=4899 容易发现树形结构是骗人的...走到错误分叉的影响是可以预处理的常数,所以就相当于一个序列 ...
- [BZOJ4899]记忆的轮廓
记忆的轮廓 题目描述 通往贤者之塔的路上,有许多的危机. 我们可以把这个地形看做是一颗树,根节点编号为1,目标节点编号为n,其中1-n的简单路径上,编号依次递增,在[1,n]中,一共有n个节点.我们把 ...
- Bzoj4899 记忆的轮廓
B. 记忆的轮廓 题目描述 通往贤者之塔的路上,有许多的危机. 我们可以把这个地形看做是一颗树,根节点编号为1,目标节点编号为n,其中1-n的简单路径上,编号依次递增,在[1,n]中,一共有n个节点. ...
- Discovering Gold LightOJ - 1030[概率dp或者记忆化搜索]
题目大意:有一个[1,n][1,n][1,n]的数轴,数轴上的每个对应位置上都有金矿,你初始位置是1,然后你每次都会投色子决定你下一步跳到哪里,如果你跳出了nnn,那么你就要重新投.问你跳到nnn的时 ...
- HDU 5001 概率DP || 记忆化搜索
2014 ACM/ICPC Asia Regional Anshan Online 给N个点,M条边组成的图,每一步能够从一个点走到相邻任一点,概率同样,问D步后没走到过每一个点的概率 概率DP 測 ...
- 【原创】概率DP总结 by kuangbin
概率DP主要用于求解期望.概率等题目. 转移方程有时候比较灵活. 一般求概率是正推,求期望是逆推.通过题目可以体会到这点. 首先先推荐几篇参考的论文: <信息学竞赛中概率问题求解初探> & ...
- 插头DP 概率DP / 期望DP
插头DP && 概率DP / 期望DP 写在前面: 插头DP P5056 [模板]插头dp 手写哈希表的方法: 拉链法的代码如下: 开放寻址法的代码如下: 接下来是这道题的代码实现: ...
- 关于概率dp的个人理解与总结
原文来自:http://blog.csdn.net/wdcjdtc/article/details/38424029 首先,概率dp主要解决的是关于概率问题和期望问题的求解. 难点和普通dp一样在于d ...
- (CCF202109-4)收集卡牌(概率DP)
题目链接:计算机软件能力认证考试系统 小林在玩一个抽卡游戏,其中有 n 种不同的卡牌,编号为 1 到 n.每一次抽卡,她获得第 i 种卡牌的概率为 pi.如果这张卡牌之前已经获得过了,就会转化为一枚硬 ...
最新文章
- ScrollView的使用
- Windows2008 R2下,DCOM配置里的属性灰色不可用的解决方法
- PHP学习系列(1)——字符串处理函数(3)
- vue @click 赋值_vue 手写一个时间选择器
- 160个Crackme016
- 你真的了解泛型 Generic 嘛?
- 如何创建php文件,PHP如何生成.php程序文件
- 任何举动之前,先思考,思考,再思考
- php取mysql某列的值,php – 获取MYSQL中某些列为null的表中的值
- Flutter进阶—自定义主题风格
- [笔记].关于使用JLINK的三线SWD模式调试NUC1xx的一点粗浅认识
- 20155226-虚拟机与Linux之初体验
- 【VRP问题】基于蚁群算法求解带时间窗车辆调度问题
- 程序员为什么要转行项目经理
- 电源芯片选择DC/DC还是LDO?
- 地塞米松/多柔比星/胡桃醌/丹皮酚-PLGA聚乳酸-羟基乙酸纳米粒
- 如何查询一个域名的子域名
- 解决:SpringBoot使用@Value读取application.properties中文乱码
- 包收录外链平台都有哪些
- 使用希沃白板5怎么上计算机课,希沃5电子白板使用教程
热门文章
- 银行人脸识别系统被攻破:43万元不翼而飞,“刷脸时代”如何防风险?
- 树莓派CSI摄像头的使用及OpenCV的简单测试
- NFC读写MifareClassic协议的NFC卡
- 北京普通中学、小学、幼儿园查询网址---普通中学、北京小学、幼儿园大全
- 一周开发一个轻量级客服系统(代码开源)
- halfstone 原理_逻辑分析仪原理及其参数介绍
- D3D12渲染技术之常量缓冲区
- java mp3 信息_android,java获取MP3文件信息(作者,专辑等)
- 在Visual Studio 2010/2012/2013/2015上使用C#开发Android/IOS安装包和操作步骤
- 摩天大楼如何靠一颗铁球防风抗震?