[pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=63399955

向大(hei)佬(e)势力学(di)习(tou)

之前一直都没有接触过期望,更别说期望dp了。

先从期望说起吧,dp什么的先不谈。浅谈一下期望的线性性(可加性),这是一个很重要的性质,主要用我做的这几道例题来更感性的理解(真的是浅谈。。。orz)

首先,期望是指一个事件有多种结果,每一种结果出现有一定的可能性。

对于随机变量x,它的期望E(x)=sigma{基本结果i发生的概率*发生基本结果i时的x的数值,i是一个基本结果}

然后是期望的线性性(可加性):

(感性理解一下)

E(X+Y)=E(X)+E(Y)

即两个(或多个)随机变量的和的期望等于期望的和

下面就由题目来理解理解吧(题才是重点):

Codeforces280c

题目大意

给出一棵含n个白点的有根树,每次随机选择一个还没有被染黑的节点,将这个节点和这个节点子树中的所有点染黑.

问期望操作多少次后所有点都被染黑.

N<=100000

整棵树的期望操作次数太大,难以找到方法。这时我们需要突破口。

该如何将大问题转化为小问题呢?我们发现,一棵树是可以分成好几颗子树的,而子树分解的最终状态就是所有的点。那么,我们是不是可以计算出 每个点被染黑的期望操作次数,然后相加就是整棵树的了?答案是当然可以。

这里需要注意的是,对于每个点的操作次数是指的在这个点上的操作。对于每一个点,如果其祖先被染黑了,它自己也会被顺带染黑,而这个对于该点来说是没有进行操作的。所以得出对于点x:E(x)=1/dep[x]

dfs就可以了

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; const int N=100000+5; int n;
int head[N],end[N*2],nxt[N*2],hh=0;
double ans=0; void dfs(int u,int f,int dep){
ans+=1.0/dep;
for(int i=head[u];i;i=nxt[i]){
int v=end[i];
if(v==f) continue;
dfs(v,u,dep+1);
}
}
void adde(int a,int b){
hh++;
end[hh]=b;
nxt[hh]=head[a];
head[a]=hh;
}
int main(){
scanf("%d",&n);
for(int i=1;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
adde(a,b),adde(b,a);
}
dfs(1,1,1);
printf("%.20lf",ans);
return 0;
}

bzoj3036绿豆蛙的归宿

Description

随着新版百度空间的下线,Blog宠物绿豆蛙完成了它的使命,去寻找它新的归宿。

给出一个有向无环的连通图,起点为1终点为N,每条边都有一个长度。绿豆蛙从起点出发,走向终点。

到达每一个顶点时,如果有K条离开该点的道路,绿豆蛙可以选择任意一条道路离开该点,并且走向每条路的概率为 1/K 。

现在绿豆蛙想知道,从起点走到终点的所经过的路径总长度期望是多少?

Input

第一行: 两个整数 N M,代表图中有N个点、M条边

第二行到第 1+M 行: 每行3个整数 a b c,代表从a到b有一条长度为c的有向边

Output

从起点到终点路径总长度的期望值,四舍五入保留两位小数。

Sample Input

4 4

1 2 1

1 3 2

2 3 3

3 4 4

Sample Output

7.00

HINT

对于100%的数据 N<=100000,M<=2*N

很显然,由期望的线性性可得:经过路径期望总长度=sigma{每条边期望经过次数*边权}

因为是有向无环图,所以 每条边的期望经过次数=该边起点的期望经过次数*从该起点出发经过该路径的概率。

于是问题转成了求每个点的期望经过次数。很显然,每个点的期望经过次数=sigma{入边i的期望经过次数}

于是发现边与点的期望值是相辅相成的关系,由于是有向无环图,所以拓扑排序就可以了

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std; const int N=100000+5; int n,m,in[N],out[N];
int head[N],end[N*2],len[N*2],nxt[N*2],hh=0;
queue<int> q;
double p[N],ans=0; void adde(int a,int b,int c){
hh++;
end[hh]=b;
len[hh]=c;
nxt[hh]=head[a];
head[a]=hh;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
adde(a,b,c);
in[b]++,out[a]++;
}
q.push(1);
p[1]=1;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i;i=nxt[i]){
int v=end[i];
ans+=p[u]/out[u]*len[i];
p[v]+=p[u]/out[u];
in[v]--;
if(in[v]==0){
q.push(v);
}
}
}
printf("%.2lf",ans);
return 0;
}

bzoj3143[Hnoi2013]游走

Description

一个无向连通图,顶点从1编号到N,边从1编号到M。

小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和。

现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小。

Input

第一行是正整数N和M,分别表示该图的顶点数 和边数,接下来M行每行是整数u,v(1≤u,v≤N),表示顶点u与顶点v之间存在一条边。 输入保证30%的数据满足N≤10,100%的数据满足2≤N≤500且是一个无向简单连通图。

Output

仅包含一个实数,表示最小的期望值,保留3位小数。

Sample Input

3 3

2 3

1 2

1 3

Sample Output

3.333

其实这道题与绿豆蛙有相似之处,但是图变为了无向连通图。

首先明确一个简单的贪心:我们希望期望经过次数最大的边编号最小。然后就是如何求期望经过次数了。原理与上一题一样,由点推边。

对于一号点,f[1]=1+sigma(f[j]/degree(j) , j和1有边)

对于其他点,f[i]=sigma(f[j]/degree(j),j和i有边)

但由于是无向图,一个点可以被经过数次,还有极小的的可能在一条边上来回走动。于是我们发现这个图是有后效性的,每个点的值会互相影响,所以不能递推。wa,那可怎么办啊?

大佬告诉我,像这种会互相影响的值,其实和方程组很像,高斯消元即可。woo,学到了。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; const int N=500+5;
const double eps=1e-10; int n,m;
int deg[N],edge[N*N][2];
int head[N],end[N*N*2],nxt[N*N*2],hh=0;
double g[N][N],p[N],ep[N*N]; void adde(int a,int b){
hh++;
end[hh]=b;
nxt[hh]=head[a];
head[a]=hh;
}
void solve(){
int cnt=0;
for(int k=1;k<n;k++){
int j=-1;
for(int i=cnt+1;i<n;i++){
if(fabs(g[i][k])>eps){
j=i;
break;
}
}
if(j==-1) continue;
cnt++;
for(int i=1;i<=n;i++) swap(g[cnt][i],g[j][i]);
for(int i=1;i<n;i++){
if(i==cnt) continue;
if(fabs(g[i][k])<eps) continue;
double tmp=g[i][k]/g[cnt][k];
for(j=1;j<=n;j++)
g[i][j]-=g[cnt][j]*tmp;
}
}
for(int i=1;i<n;i++){
p[i]=g[i][n]/g[i][i];
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int a,b;
scanf("%d%d",&a,&b);
adde(a,b),adde(b,a);
deg[a]++,deg[b]++;
edge[i][0]=a,edge[i][1]=b;
}
for(int i=head[1];i;i=nxt[i]){
int v=end[i];
if(v==n) continue;
g[1][v]=1.0/deg[v];
}
g[1][1]=-1;
g[1][n]=-1;
for(int k=2;k<n;k++){
g[k][k]=-1;
for(int i=head[k];i;i=nxt[i]){
int v=end[i];
if(v==n) continue;
g[k][v]=1.0/deg[v];
}
}
solve();
for(int i=1;i<=m;i++){
int a=edge[i][0],b=edge[i][1];
ep[i]=p[a]/deg[a]+p[b]/deg[b];
}
sort(ep+1,ep+m+1);
double ans=0;
for(int i=1;i<=m;i++){
ans+=ep[i]*(m-i+1);
}
printf("%.3lf",ans);
return 0;
}

总结:

1、分解成小的、可计算的期望问题,来解决大的、不可计算的期望问题

2、无后效性的可直接递推。有后效性的可解方程。

浅谈期望的线性性(可加性)【CodeForces280c】【bzoj3036】【bzoj3143】的更多相关文章

  1. bzoj1415[NOI2005]聪聪和可可-期望的线性性

    这道题之前我写过一个巨逗比的写法(传送门:http://www.cnblogs.com/liu-runda/p/6220381.html) 当时的原因是这道题可以抽象出和"绿豆蛙的归宿&qu ...

  2. 【NOIP2019模拟2019.9.4】B(期望的线性性)

    题目描述: \(1<=n,ai<=5*10^5\) 题解: 我是弱智我不会期望线性. 设\(E(a[i])\)表示第i个期望被减的个数. \(E(a[1])=a[1]\) 不难发现\(E( ...

  3. 2019牛客暑期多校训练营(第八场)B-Beauty Values(期望线性性)

    >传送门< 题意:思路:期望的线性性(可加性),比赛的时候写的代码超级无敌长,不过值得欣慰的是一发AC了,官方的题解写的还不错~ 我们可以把每种数字对答案的贡献分开来计算,即枚举每个数字, ...

  4. cf280C. Game on Tree(期望线性性)

    题意 题目链接 Sol 开始想的dp,发现根本不能转移(貌似只能做链) 根据期望的线性性,其中\(ans = \sum_{1 * f(x)}\) \(f(x)\)表示删除\(x\)节点的概率,显然\( ...

  5. 【架构】浅谈web网站架构演变过程

    浅谈web网站架构演变过程   前言 我们以javaweb为例,来搭建一个简单的电商系统,看看这个系统可以如何一步步演变.   该系统具备的功能:   用户模块:用户注册和管理 商品模块:商品展示和管 ...

  6. 【SqlServer系列】浅谈SQL Server事务与锁(上篇)

    一  概述 在数据库方面,对于非DBA的程序员来说,事务与锁是一大难点,针对该难点,本篇文章视图采用图文的方式来与大家一起探讨. “浅谈SQL Server 事务与锁”这个专题共分两篇,上篇主讲事务及 ...

  7. 浅谈分词算法(4)基于字的分词方法(CRF)

    目录 前言 目录 条件随机场(conditional random field CRF) 核心点 线性链条件随机场 简化形式 CRF分词 CRF VS HMM 代码实现 训练代码 实验结果 参考文献 ...

  8. 浅谈 JavaScript 编程语言的编码规范

    对于熟悉 C/C++ 或 Java 语言的工程师来说,JavaScript 显得灵活,简单易懂,对代码的格式的要求也相对松散.很容易学习,并运用到自己的代码中.也正因为这样,JavaScript 的编 ...

  9. 重新学习MySQL数据库6:浅谈MySQL的中事务与锁

    『浅入深出』MySQL 中事务的实现 在关系型数据库中,事务的重要性不言而喻,只要对数据库稍有了解的人都知道事务具有 ACID 四个基本属性,而我们不知道的可能就是数据库是如何实现这四个属性的:在这篇 ...

随机推荐

  1. Multiple HTTPS Bindings IIS 7 Using appcmd

    http://toastergremlin.com/?p=308 Sometimes when using a wildcard SSL or Unified Communications Certi ...

  2. 4 - django-orm基本使用

    目录 1 数据库与ORM 2 orm的配置 2.1 引擎和配置 2.2 mysql驱动程序 3 orm 表模型 3.1 创建表对象 3.2 Django字段类型 3.3 常用字段参数说明 3.4 特殊 ...

  3. shell脚本实现分日志级别输出

    shell脚本如何优雅的记录日志信息,下面让我们一步一步,让shell脚本的日志也变得高端起来,实现如下功能 ①设定日志级别,实现可以输出不同级别的日志信息,方便调试 ②日志格式类似为:[日志级别] ...

  4. USB descriptor【转】

    struct usb_device_descriptor { __u8 bLength;//设备描述符的字节数大小,为0x12 __u8 bDescriptorType;//描述符类型编号,为0x01 ...

  5. CentOS7 修改网卡名称

    vi /etc/sysconfig/grub 增加net.ifnames=0 biosdevname=0 执行:grub2-mkconfig -o /boot/grub2/grub.cfg

  6. python网络编程-socketserver

    一:socketserver简化了网络服务器的编写. 它有4个类:TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer. 这4个类是同步进行处 ...

  7. 洛谷P3119 草鉴定

    这个题调了一天.. 传送门 读完题目之后我们不难想出这个题是个tarjan缩点问题,因为尽量多的经过草场,所以一号点所在的强连通分量里左右的点都是不需要在进行走逆向边,所能到达的. 然后问题就落在怎么 ...

  8. linux nat网络配置

    1. 2 . 3. BOOTPROTO = static ONBOOT=yes  #开启自动启用网络连接 IPADDR0=192.168.21.128  #设置IP地址 PREFIXO0=24  #设 ...

  9. Python学习笔记:bisect模块实现二分搜索

    在Python中可以利用bisect模块来实现二分搜索,该模块包含函数只有几个: import bisect L = [1,3,4,5,5,5,8,10] x = 5 bisect.bisect_le ...

  10. 能ping但是无法上网

    管理员权限,执行以下这个命令就好了. netsh winsock reset 配置问题,重置windows socket.