BZOJ1415 [Noi2005]聪聪和可可
Posted ONION_CYC
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ1415 [Noi2005]聪聪和可可相关的知识,希望对你有一定的参考价值。
【算法】期望DP,记忆化搜索 题目
【题解】浅析竞赛中一类数学期望问题的解决方法 例题
首先因为聪聪走的步数等于大于可可走的步数,所以不可能出现循环(高斯消元),使DP成为可能。
因为是图显然采用记忆化搜索。
p[x][y]表示x走向y第一步编号,f[x][y]表示答案(把答案数组设置出来考虑倒序递推就顺理成章了)。
e[x][y]表示x的相邻点(代码实现用邻接表),t[x]表示x的度(邻点个数)。
if(x==y)f[x][y]=0;
if(p[p[x][y]][y]==y||p[x][y]==y)f[x][y]=1;
f[x][y]=(Σf[p[p[x][y]][y]][e[y][wi]+f[p[p[x][y]][y]][y])/(t[y]+1)+1(在公式中多走一步+1也是套路)
期望数组记得double。
当无边权时,最短路问题就可以用bfs。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=1010; struct edge{int from,v;}e[maxn*3]; int n,m,a,b,ins[maxn],first[maxn],d[maxn],q[1010],p[maxn][maxn],tot; double f[maxn][maxn]; void insert(int u,int v) { tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;ins[u]++; tot++;e[tot].v=u;e[tot].from=first[v];first[v]=tot;ins[v]++; } double dp(int a,int b) { if(f[a][b])return f[a][b]; if(a==b)return f[a][b]=0; if(p[a][b]==b||p[p[a][b]][b]==b)return f[a][b]=1; double ans=dp(p[p[a][b]][b],b); for(int i=first[b];i;i=e[i].from) ans+=dp(p[p[a][b]][b],e[i].v); return f[a][b]=ans/(1.0*ins[b]+1)+1; } void bfs(int x) { memset(d,-1,sizeof(d)); int head=0,tail=0;d[x]=0;p[x][x]=0; for(int i=first[x];i;i=e[i].from)p[x][e[i].v]=e[i].v,d[e[i].v]=1,q[tail++]=e[i].v; while(head!=tail) { int y=q[head++];if(head>1000)head=0;int num=p[x][y]; for(int i=first[y];i;i=e[i].from) if(d[e[i].v]==-1||((d[y]+1==d[e[i].v])&&num<p[x][e[i].v])) { d[e[i].v]=d[y]+1; p[x][e[i].v]=num; q[tail++]=e[i].v; if(tail>1000)tail=0; } } } int main() { scanf("%d%d%d%d",&n,&m,&a,&b); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); insert(u,v); } for(int i=1;i<=n;i++)bfs(i); printf("%.3lf",dp(a,b)); return 0; }
以上是关于BZOJ1415 [Noi2005]聪聪和可可的主要内容,如果未能解决你的问题,请参考以下文章