【总结】待定系数求解高斯消元

摘要:运用待定系数法建立方程求解期望值。

「HDU4035」Maze

本题 n n n 比较大,很难用高斯消元求解。

考虑叶子节点,有关系式:

d p [ i ] = k [ i ] ∗ d p [ 1 ] + ( 1 − k [ i ] − e [ i ] ) ( d p [ f a [ i ] ] + 1 ) dp[i]=k[i]*dp[1] + (1-k[i]-e[i]) (dp[fa[i]]+1) dp[i]=k[i]dp[1]+(1k[i]e[i])(dp[fa[i]]+1)

这启发我们用待定系数法来求解。

一般地,设 d p [ i ] = A [ i ] ∗ d p [ 1 ] + B [ i ] ∗ d p [ f a [ i ] ] + C [ i ] dp[i]=A[i]*dp[1] + B[i]*dp[fa[i]] + C[i] dp[i]=A[i]dp[1]+B[i]dp[fa[i]]+C[i]

对于一般的节点,有转移式:

d p [ i ] = k [ i ] ∗ d p [ 1 ] + ( 1 − e [ i ] − k [ i ] ) ∗ ∑ j ∈ s o n ( i ) ( d p [ j ] + 1 ) m dp[i]=k[i]*dp[1]+\frac{(1-e[i]-k[i])*\sum_{j\in son(i)}(dp[j]+1)}{m} dp[i]=k[i]dp[1]+m(1e[i]k[i])json(i)(dp[j]+1)

最后再解一个方程即可。

#include<bits/stdc++.h> #define db double using namespace std; const int Maxn=10005; const db eps=1e-9; int T,n,Case,in[Maxn]; db e[Maxn],k[Maxn]; db A[Maxn],B[Maxn],C[Maxn],D[Maxn]; vector<int> g[Maxn]; bool dfs(int x,int fa) { A[x]=B[x]=C[x]=D[x]=0; int m=g[x].size(); A[x]=k[x]; B[x]=(1-k[x]-e[x])/m; C[x]=1-k[x]-e[x]; for(auto y:g[x]) { if(y==fa) continue; if(!dfs(y,x)) return 0; A[x]+=(1-k[x]-e[x])/m*A[y]; D[x]+=(1-k[x]-e[x])/m*B[y]; C[x]+=(1-k[x]-e[x])/m*C[y]; } if(fabs(D[x]-1)<=eps) { return 0; } A[x]/=1-D[x]; B[x]/=1-D[x]; C[x]/=1-D[x]; return 1; } int main() { // freopen("1.in","r",stdin); scanf("%d",&T); while(T--) { int flg=0; scanf("%d",&n); for(int i=1;i<=n;i++) in[i]=0,g[i].clear(); for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); in[u]++,in[v]++; } for(int i=1;i<=n;i++) { scanf("%lf%lf",&k[i],&e[i]); e[i]/=100; k[i]/=100; } if(!dfs(1,0)||fabs(A[1]-1)<=eps) { printf("Case %d: impossible\n",++Case); } else { printf("Case %d: %.6lf\n",++Case,C[1]/(1-A[1])); } } }

「ZOJ3329」One Person Game

考虑逆推。

d p [ i ] dp[i] dp[i] 表示当前在第 i i i 格时到达终点的期望步数。

设骰子为 (a,b,c) 的概率为 p0 ,否则总和为 j 的概率为 pj 。

不难得到这样的式子:

d p [ i ] = ∑ j = 0 a + b + c p [ j ] ∗ d p [ i + j ] + p [ 0 ] ∗ d p [ 1 ] dp[i]=\sum_{j=0}^{a+b+c}p[j]*dp[i+j]+p[0]*dp[1] dp[i]=j=0a+b+cp[j]dp[i+j]+p[0]dp[1]

直接消元时间复杂度 O ( n 3 ) O(n^3) O(n3)

观察到每一项都和 d p [ 0 ] dp[0] dp[0] 有关。

d p [ i ] = A [ i ] ∗ d p [ 0 ] + B [ i ] dp[i]=A[i]*dp[0]+B[i] dp[i]=A[i]dp[0]+B[i]

A[i] , B[i] 不难递推得到。

最后解出 d p [ 0 ] dp[0] dp[0] 的方程即可。

总结:本题设而不求时关键。以及递推思想的运用。

#include<bits/stdc++.h> #define db double using namespace std; const int Maxn=505; int T,n,k1,k2,k3,a,b,c; db A[Maxn],B[Maxn],p[Maxn]; int main() { scanf("%d",&T); while(T--) { scanf("%d%d%d%d%d%d%d",&n,&k1,&k2,&k3,&a,&b,&c); A[n+1]=B[n+1]=0; p[0]=1.0/k1/k2/k3; for(int i=1;i<=k1+k2+k3;i++) p[i]=0; for(int i=1;i<=k1;i++) { for(int j=1;j<=k2;j++) { for(int k=1;k<=k3;k++) { if(i==a&&j==b&&k==c) continue; p[i+j+k]+=1.0/k1/k2/k3; } } } for(int i=n;i>=0;i--) { A[i]=p[0]; B[i]=1; for(int j=1;j<=k1+k2+k3;j++) { if(i+j>n) continue; A[i]+=p[j]*A[i+j]; B[i]+=p[j]*B[i+j]; } } printf("%.12lf\n",B[0]/(1-A[0])); } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530223.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(10)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示