本来先做的聪聪与可可,然后没做出来去做的4284,然后又看了看换根dp,然后又看了看spfa,我tcl
注意计算概率时需要考虑是否要用容斥原理,期望dp时注意有时要用倒序枚举
P4284概率充电器
我们可以把总的期望个数转化为每个点对答案的贡献,如果某个点被点亮贡献为1,否则为0,所以我们只要求出每个点被点亮的概率即可
设(p[u])是点(u)亮的概率,一条边能通电概率为(e[u,v])
那么化式子的时候有很多类似(1-P)的式子,所以我们设(p[u])是u不亮的概率(正难则反)昂神最喜欢说了:)逃
(p[u]=(1-q[u])prod_{(u,v)in E}(1-e[u,v]+e[u,v][p,v]))
式子有依赖,giao斯小猿吗,可吧
但选择(树形DP换根)就完了,pj神勃客写过qwq,先把无根树随便定根,设(f[u]为u不被它子树(含自身)的点点亮的概率)
(f[u]=(1-q[u])prod_{v in son[u]}(1-e[u,v]+e[u,v]f[v]))
(跑一遍dfs,定下根的答案,但其他点的答案还不正确,考虑把根换成u)
设(g[u])是以(u)为根时(u)不被点亮的概率,很显然分为两部分:(u)原来的子树,剩下的部分,(u)原来的子树我们已经得到了,剩下的部分可以通过(g[fa])去掉u的贡献得到
(P(rest)=g[fa]/(1-e[fa,u]+e[fa,u]f[u]))
那么(g[u]=f[u(l-e[fa,u]+e[fa,u]P(rest))])
(最后u的概率为1-g[u])
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=2e6;
struct Edge{int v;double w;}e[N];
int mm,n,fst[N],nxt[N];
double p[N],f[N],g[N];
void ade(int u,int v,double w){e[++mm]=(Edge){v,w};nxt[mm]=fst[u],fst[u]=mm;}
void dfs1(int u,int fa)
{
f[u]=1-p[u];
for(int i=fst[u];i;i=nxt[i])
{
int v=e[i].v;
if(v==fa)continue;
dfs1(v,u);
f[u]*=(1-e[i].w+e[i].w*f[v]);
}
}
void dfs2(int u,int fa,int ei)
{
if(u==1)g[u]=f[u];//如果u是根,那么什么都不用管.
else
{
double P=g[fa]/(1-e[ei].w+e[ei].w*f[u]);
g[u]=f[u]*(1-e[ei].w+e[ei].w*P);
}
for(int i=fst[u];i;i=nxt[i])
{
int v=e[i].v;
if(v==fa)continue;
dfs2(v,u,i);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
ade(u,v,w*0.01),ade(v,u,w*0.01);
}
for(int i=1;i<=n;i++)scanf("%lf",p+i),p[i]*=0.01;
dfs1(1,0),dfs2(1,0,0);double ans=0;
for(int i=1;i<=n;i++)ans+=1-g[i];
printf("%.6lf",ans);
}
P4206聪聪与可可
猫可以走一步或两步;老鼠可以不动;猫必须走到离老鼠最近的点,如距离有相同,则选编号最小的点
预处理:预处理猫在(i),老鼠在(j),的下一个走位(nxt[i][j]),(SPFA预处理出最短路径dis[i][j]),接下来才能预处理猫的走位
等等我有点乱,先咕着