B. 记忆的轮廓

题目描述

通往贤者之塔的路上,有许多的危机。
我们可以把这个地形看做是一颗树,根节点编号为1,目标节点编号为n,其中1-n的简单路径上,编号依次递增,在[1,n]中,一共有n个节点。我们把编号在[1,n]的叫做正确节点,[n+1,m]的叫做错误节点。一个叶子,如果是正确节点则为正确叶子,否则称为错误叶子。莎缇拉要帮助昴到达贤者之塔,因此现在面临着存档位置设定的问题。
为了让昴成长为英雄,因此一共只有p次存档的机会,其中1和n必须存档。被莎缇拉设置为要存档的节点称为存档位置。当然不能让昴陷入死循环,所以存档只能在正确节点上进行,而且同一个节点不能存多次档。因为通往贤者之塔的路上有影响的瘴气,因此莎缇拉假设昴每次位于树上一个节点时,都会等概率选择一个儿子走下去。每当走到一个错误叶子时,再走一步就会读档。具体的,每次昴到达一个新的存档位置,存档点便会更新为这个位置(假如现在的存档点是i,现在走到了一个存档位置j>i,那么存档点便会更新为j)。读档的意思就是回到当前存档点。初始昴位于1,当昴走到正确节点n时,便结束了路程。莎缇拉想知道,最优情况下,昴结束路程的期望步数是多少?

输入格式

第一行一个正整数T表示数据组数。
接下来每组数据,首先读入三个正整数n,m,p。
接下来m-n行,描述树上所有的非正确边(正确边即连接两个正确节点的边)
用两个正整数j,k表示j与k之间有一条连边,j和k可以均为错误节点,也可以一个为正确节点另一个为错误节点。
数据保证j是k的父亲。
50<=p<=n<=700,m<=1500,T<=5。
数据保证每个正确节点均有至少2个儿子,至多3个儿子。

输出格式

T行每行一个实数表示每组数据的答案。请保留四位小数。

样例

样例输入

1
3 7 2
1 4
2 5
3 6
3 7

样例输出

9.0000

orz大佬题解:https://blog.csdn.net/WerKeyTom_FTD/article/details/53026266

我这里只是梳理一下自己的思路。

50算法

  对于n==p的情况,就是在每一个点都存档,设d[i]表示节点i的儿子数,对于错误节点i,设g[i]为读档的期望步数,则g[i]=1+∑(1/d[i]*g[j]).对于正确节点i,设s[i]=∑g[j](j为i的错误儿子)。设f[i]为从i到n的期望步数,f[n]=0,f[i]=1+f[i+1]/d[i]+∑(g[j]+f[i])/d[i],得f[i]=d[i]+f[i+1]+s[i];

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
struct edge
{int u,v,next;#define u(x) ed[x].u#define v(x) ed[x].v#define n(x) ed[x].next
}ed[200010];
int first[100010],num_e;
#define f(x) first[x]
int T;
int n,m,p;
double d[100000],g[100000],s[100000],f[100000];void dfs(int x,int fa)
{//cout<<x<<" "<<fa<<endl;if(x>n)g[x]=1;for(int i=f(x);i;i=n(i))if(v(i)!=fa)d[x]++;for(int i=f(x);i;i=n(i))if(v(i)!=fa){dfs(v(i),x);if(x>n)g[x]+=1/d[x]*g[v(i)];else   s[x]+=g[v(i)];}if(x<n)    f[x]=d[x]+s[x]+f[x+1];
}
inline void add(int u,int v);
signed main()
{cin>>T;while(T--){cin>>n>>m>>p;for(int i=1;i<n;i++)add(i,i+1),add(i+1,i);int u,v;for(int i=1;i<=m-n;i++){cin>>u>>v;add(u,v),add(v,u);}if(n==p){dfs(1,0);printf("%0.4lf\n",f[1]);}}}
inline void add(int u,int v)
{++num_e;u(num_e)=u;v(num_e)=v;n(num_e)=f(u);f(u)=num_e;
}

View Code

70算法

   设a[i][j]为当前存档点为i,从i出发到j的期望步数,用n2的复杂度预处理出a,a[i][i]=0,对于i<j,a[i][j]=a[i][j-1]+1+1/d[j-1]*0+∑(g[k]+a[i][j])/d[j-1];(k为j-1的错误儿子),得a[i][j]=a[i][j-1]*d[j-1]+d[j-1]+s[j-1];这里理解了好长时间,我本来写的是a[i][j]=a[i][j-1]+1/d[j-1]+∑(g[k]+a[i][j])/d[j-1];因为从j-1无论如何都要再走一步到他的儿子节点,我是忘了这个……设f[i][j]表示当前存档点为i,还剩j次存档机会,到n的期望步数,

那么f[i][j]=min(f[k][j-1]+a[i][k]),i<k<=n;最后答案为f[1][p-1];复杂度O(n2p);

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define ma(x) memset(x,0,sizeof(x))
using namespace std;
struct edge
{int u,v,next;#define u(x) ed[x].u#define v(x) ed[x].v#define n(x) ed[x].next
}ed[20010];
int first[1510],num_e;
#define f(x) first[x]
int T;
int n,m,p;
double d[1510],g[1510],s[1510],f[1510];double a[710][710],f2[710][710];void dfs(int x,int fa);
inline void add(int u,int v);
signed main()
{//freopen("5.in","r",stdin);
    cin>>T;while(T--){num_e=0;ma(d);ma(g);ma(s);ma(f);ma(f2);ma(a);ma(first);cin>>n>>m>>p;for(int i=1;i<n;i++)add(i,i+1),add(i+1,i);int u,v;for(int i=1;i<=m-n;i++){scanf("%d%d",&u,&v);add(u,v),add(v,u);}dfs(1,0);if(n==p){printf("%0.4lf\n",f[1]);continue;}for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)a[i][j]=a[i][j-1]*d[j-1]+d[j-1]+s[j-1];for(int i=n-1;i;i--)for(int j=0;j<=p;j++)f2[i][j]=0x7fffffff;for(int i=n;i>=1;i--)for(int j=1;j<p;j++)for(int k=i+1;k<=n;k++)f2[i][j]=min(f2[i][j] , f2[k][j-1]+a[i][k] );printf("%0.4lf\n",f2[1][p-1]);}}
inline void add(int u,int v)
{++num_e;u(num_e)=u;v(num_e)=v;n(num_e)=f(u);f(u)=num_e;
}
void dfs(int x,int fa)
{if(x>n)g[x]=1;for(int i=f(x);i;i=n(i))if(v(i)!=fa){d[x]++;//cout<<i<<" "<<v(i)<<endl;
    }//cout<<x<<endl;for(int i=f(x);i;i=n(i))if(v(i)!=fa){dfs(v(i),x);if(x>n)g[x]+=1/d[x]*g[v(i)];else   s[x]+=g[v(i)];}if(x<n)    f[x]=d[x]+s[x]+f[x+1];
}

View Code

70算法+玄学优化AC

  题解的分析没有看懂,就是证明了一下a数组不会爆炸的问题,a的增长是非常快的,但答案并不会有那么大,所以可以假定一个常数step,每次转移最多从距离step转移过来,step取40就差不多了,因为a的下界是2^40了,而答案的上界远远没有达到。题解说复杂度是O(np log ans),没有搞懂,O(40np)更容易理解吧,其实也差不多。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define ma(x) memset(x,0,sizeof(x))
using namespace std;
struct edge
{int u,v,next;#define u(x) ed[x].u#define v(x) ed[x].v#define n(x) ed[x].next
}ed[20010];
int first[1510],num_e;
#define f(x) first[x]
int T;
int n,m,p;
double d[1510],g[1510],s[1510],f[1510];double a[710][710],f2[710][710];
const int step=40;void dfs(int x,int fa);
inline void add(int u,int v);
signed main()
{//freopen("5.in","r",stdin);
    cin>>T;while(T--){num_e=0;ma(d);ma(g);ma(s);ma(f);ma(f2);ma(a);ma(first);cin>>n>>m>>p;for(int i=1;i<n;i++)add(i,i+1),add(i+1,i);int u,v;for(int i=1;i<=m-n;i++){scanf("%d%d",&u,&v);add(u,v),add(v,u);}dfs(1,0);if(n==p){printf("%0.4lf\n",f[1]);continue;}for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)a[i][j]=a[i][j-1]*d[j-1]+d[j-1]+s[j-1];for(int i=n-1;i;i--)for(int j=0;j<=p;j++)f2[i][j]=0x7fffffff;for(int i=n;i>=1;i--)for(int j=1;j<p;j++)for(int k=i+1;k<=min(i+step,n);k++)f2[i][j]=min(f2[i][j] , f2[k][j-1]+a[i][k] );printf("%0.4lf\n",f2[1][p-1]);}}
inline void add(int u,int v)
{++num_e;u(num_e)=u;v(num_e)=v;n(num_e)=f(u);f(u)=num_e;
}
void dfs(int x,int fa)
{if(x>n)g[x]=1;for(int i=f(x);i;i=n(i))if(v(i)!=fa)d[x]++;for(int i=f(x);i;i=n(i))if(v(i)!=fa){dfs(v(i),x);if(x>n)g[x]+=1/d[x]*g[v(i)];else   s[x]+=g[v(i)];}if(x<n)    f[x]=d[x]+s[x]+f[x+1];
}

View Code

100算法

  居然是个单队。首先证明a[i][j+1]-a[i][j]>=a[i+1][j+1]-a[i+1][j],把a[i][j+1]展开,得左边=(d[j]-1)*a[i][j]+…,右边=(d[j]-1)*a[i+1][j]+…。得证。则可以用单队优化,复杂度O(np log n)。

另外还有一种做法,目前还没有看懂……

转载于:https://www.cnblogs.com/Al-Ca/p/11046025.html

Bzoj4899 记忆的轮廓相关推荐

  1. [BZOJ4899]:记忆的轮廓(概率DP)

    题目传送门 题目描述: 通往贤者之塔的路上,有许多的危机. 我们可以把这个地形看做是一颗树,根节点编号为1,目标节点编号为n,其中1-n的简单路径上,编号依次递增, 在[1,n]中,一共有n个节点.我 ...

  2. [BZOJ4899]记忆的轮廓

    记忆的轮廓 题目描述 通往贤者之塔的路上,有许多的危机. 我们可以把这个地形看做是一颗树,根节点编号为1,目标节点编号为n,其中1-n的简单路径上,编号依次递增,在[1,n]中,一共有n个节点.我们把 ...

  3. BZOJ4899: 记忆的轮廓 期望DP 决策单调性

    题意:http://www.lydsy.com/JudgeOnline/problem.php?id=4899 容易发现树形结构是骗人的...走到错误分叉的影响是可以预处理的常数,所以就相当于一个序列 ...

  4. 4899: 记忆的轮廓

    4899: 记忆的轮廓 Time Limit: 5 Sec Memory Limit: 512 MB Submit: 134 Solved: 51 [Submit][Status][Discuss] ...

  5. 【BZOJ4899】记忆的轮廓

    [题目链接] 点击打开链接 [思路要点] 预处理出costi,jcosti,jcost_{i,j}表示存档点i,ji,ji,j之间不存在其它存档点时,从iii走到j" role=" ...

  6. 基础省选+NOI-第4部分 动态规划

    1.期望概率DP [整理]简单的数学期望和概率DP [整理]简单的数学期望和概率DP - nimphy - 博客园 期望&概率dp总结 期望&概率dp总结_十分残念的博客-CSDN博客 ...

  7. 省选+NOI 第一部分 动态规划DP

    期望概率DP [整理]简单的数学期望和概率DP [整理]简单的数学期望和概率DP - nimphy - 博客园 期望&概率dp总结 期望&概率dp总结_十分残念的博客-CSDN博客 期 ...

  8. CES 2017前瞻之AI:无人机依旧小巧,机器人主打家庭服务

    再过2天,CES 2017就要开始了,根据这些已知晓的部分展商,我们也许能够看到未来的一些趋势. 还有2天,备受瞩目的CES 2017(2017年国际消费类电子产品展览会)就要拉开帷幕了. 每一年,C ...

  9. 致我们终将逝去的青春

    致我们终将逝去的青春 踩着素白的雾霭起步,晨曦的彩霞落寞地逼向幻想,沿着夕阳殊途的文脉,光阴碎落在记忆的轮廓里.让我们捡着星星的碎片,一起踏上这段追寻青春的记忆-- 冗长的雨季中,一个梦境重叠着另一个 ...

最新文章

  1. 如何成为Android开发高手
  2. 如何安全地吃掉悬崖边上的苹果?DeepMindOpenAI给出3D版安全强化学习答案
  3. 服务器功率一般多少_单机柜供电能力提升后,选择1U服务器还是2U服务器?
  4. CentOS7安装Zabbix
  5. SpringBoot任务调度案例(学习笔记)
  6. js中父窗口获得模态窗口的返回值
  7. 故障模块名称kernelbase.dll_西门子PLC数字量DI扩展模块1221一级总代理
  8. Python二级笔记(6)
  9. 1.5 编程基础之循环控制(45题)
  10. Flutter使用ScreenUtil获取屏幕宽高初始化报错
  11. 春天到了,减肥机器人也到了。
  12. Java复习总结(一)思维导图
  13. 水很深的深度学习-Task05循环神经网络RNN
  14. 机器学习人才的职业薪酬也发展
  15. FR复选框批量删除(填报)
  16. Idea Debug 时 JAVA对象转Json字符串 的操作
  17. netty权威指南---编解码技术
  18. 【无人机组装与调试】第六章 电调、电池、电机
  19. 第三章 概念模型设计(一)
  20. 算法导论8.4-4-单位圆中均匀分布情况--桶排序

热门文章

  1. 关于remove和removeat
  2. JavaScript的OO思想(一)
  3. qq登录钓鱼php网页,PHP+JS模仿登录钓鱼
  4. python 请在微信客户端打开_当 Python 遇到微信
  5. qpython3l安装包下载_python安装包 官方版
  6. ★寒门再难出贵子?太现实了!【下】
  7. mysql配置修改_mysql配置修改
  8. semantic ui html5,css中什么是Semantic UI框架?
  9. python实现画板_一起看看python+pygame简单画板实现代码实例
  10. 【ROS学习笔记】11.服务数据(srv)的定义与使用