其实这个东西,就是根据 对于能从那个状态转移过来,及其转移代价之和除以概率的和。。。
因为期望的线性性质。。。
就可以算出来。。。。。
我这篇东西写的太垃圾了,推荐把题做了,不会做去别的地方看题解,不要看我的题解,,写的贼垃圾,,,,,(我文学造诣真的低。。。。)
例题A. [LightOJ-1038]
一句话题意:让你求一个数n,每次除他的一个因子,问你变成1的期望步数。。。。
其实你可以把这个东西当成图看。。。
然后呢,就会发现。。。直接拿与他相连的点把当前点算出来就好了。。。。
转移方程:
#include<bits/stdc++.h>
#define MAXN 100000
using namespace std;
//题意:让你求一个数 每次除于他的因数,最后变成1的期望步数
int T,n,cishu;
double f[MAXN+5],sum,dx;
int main(){
for(int i=2;i<=MAXN;i++){
sum = 0;dx = -1;
for(int j=1;j*j<=i;j++){
if(i%j==0){
sum+=f[i/j]+1,dx++;
if(i/j!=j)sum+=f[j]+1,dx++;
}
}
f[i] = (sum)/dx;
}
cin>>T;
while(T--){
cishu++;
cin>>n;
cout<<"Case "<<cishu<<": ";
printf("%.7f\n",f[n]);
}
}
lightoj的题都挺好的,推荐板刷
例题B.POJ - 2096
一句话题意:一个软件有s个子系统,会产生n种bug。
某人一天发现一个bug,这个bug属于某种bug,发生在某个子系统中。
求找到所有的n种bug,且每个子系统都找到bug,这样所要的天数的期望。
需要注意的是:bug的数量是无穷大的,所以发现一个bug,出现在某个子系统的概率是1/s,
属于某种类型的概率是1/n。(这个是摘抄某位大佬的。。。)
很显然,我们有状态:
转移比较好想把
出现在之前的系统,且出现在之前的bug
出现在之前的系统,且出现新的bug
出现在新的系统,且出现在之前的bug
出现在新的系统,且出现新的bug
可以做了,,,,
markdown好恶心啊。。。。
好吧。。。。上面的要逆推。。。
一般来说,求期望是逆推,概率是正推。。。。mmp
注意,dp方程可能一次转移会转移回自己,注意移项。。。。。
注意,,,,可以移项。。。。(我之前忘记可以移项。。。。看题解懵逼了半天。。。。然后自己调,调的心态爆炸。。。)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define MAXN 1005
using namespace std;
double n,m;
double f[MAXN][MAXN];
int main(){
int zz1,zz2;
while(scanf("%d%d" , &zz1 , &zz2) == 2){
memset(f , 1 , sizeof(f));
n = zz1;
m = zz2;
for(int i = n ; i >= 0 ; i--){
for(int j = m ; j >= 0 ; j--){
if(i == n && j == m)continue;
double tot = 1;
tot += (f[i + 1][j] * (n - i) * j) / (n * m);
tot += (f[i][j + 1] * i * (m - j)) / (n * m);
tot += (f[i + 1][j + 1] * (n - i) * (m - j)) / (n * m);
f[i][j] = tot * n * m / (n * m - i * j);
}
}
printf("%.4f\n" , f[0][0]);
}
}
例题3.ZOJ - 3329
题意:给你三个色子,然后呢,每个色子有ki个面。。。。有个计数器,每次只要没甩到给定的a,b,c计数器不会清零(此时不加abc的三倍) 不然就加上甩到的和的三倍,大于n就结束。。。
n<=500
注意到这个n很小。。。。而且维护次数的话做不了
于是就拿计数器作为状态。。。。
然后我们又发现,k<=6
于是乎。。。。每次转移
似乎也没什么问题。。。。。
但会出现f(0)这种恶心的情况。。。。。于是乎,我们可以尝试通过把之前那个式子移项?算出来
易有
发现f(0)这里是个常数(也说不上是常数把。。。。。就是那种求不出来的值,就不好办了呀。。。。)
于是乎,要想办法怎么把f(0)搞出来。。。。
不妨分离一下系数。。。。。(意思就是拿f(0)作为主要的,其他的全部设成递推式。。。。)
(其实这里我也很懵逼。。。。。嘛,不过我的确是想要通过f函数的递推关系来搞。。。。但我没尝试啊。。。。毕竟推导比较恶心。。。)
不过这个题真的挺好的啊。。。。517牛逼~
#include<bits/stdc++.h>
#define MAXN 505
using namespace std;
int T;
int n,a,b,c;
double A[MAXN],B[MAXN],p[MAXN*5],dan,k[4];
/*
ÏÈÔ¤´¦Àí³öÿ¸öÊý³öÏֵĸÅÂÊ
È»ºóÔÙ¸ù¾ÝתÒÆʽ×ÓÀ´µÝÍÆ
*/
void solve(){
for(int now = n ; now >= 0 ; now--){
A[now] = dan;
B[now] = 1;
for(int i = 1 ; i <= (k[1] + k[2] + k[3]) ; i++){
A[now] += A[now + i] * p[i];
B[now] += B[now + i] * p[i];
}
}
}
int main(){
cin>>T;
while(T--){
memset(A , 0 , sizeof(A));
memset(B , 0 , sizeof(B));
memset(p , 0 , sizeof(p));
cin>>n>>k[1]>>k[2]>>k[3]>>a>>b>>c;
dan = (1.0 / (k[1] * k[2] * k[3]));
for(int k1 = 1 ; k1 <= k[1] ; k1++){
for(int k2 = 1 ; k2 <= k[2] ; k2++){
for(int k3 = 1 ; k3 <= k[3] ; k3++){
if(k1 == a && k2 == b && k3 == c)continue;
p[k1 + k2 + k3] += dan;
}
}
}
solve();
printf("%.16lf\n" , B[0] / (1 - A[0]));
}
}