一般形成环的用高斯消元法求解。但是递推公式只和少数变量相关,可以考虑分离出系数。
1.这类题型一般可以先写出原始公式然后分离出困难的变量,比如第二题的 dp[1] , dp[father[i]] , 都是很难处理的变量,就可以把它们作为待定系数的变量
2.将剩下的变量通过待定系数的公式带入消去,比如例题2, ∑dp[child[i]] 用 ∑(Aj∗dp[1]+Bj∗dp[i]+Cj) (j=child[i])带入消去,从而找到关于系数A,B,C的递推公式
3.写出结果公式*用递推出的系数求出结果
例题1:HDU4405
题意:有三个骰子,分别有k1,k2,k3个面。
每次掷骰子,如果三个面分别为a,b,c则分数置0,否则加上三个骰子的分数之和。
当分数大于n时结束。求游戏的期望步数。初始分数为0
设dp[i]表示达到i分时到达目标状态的期望,pk为投掷k分的概率,p0为回到0的概率
则dp[i]=∑(pk*dp[i+k])+dp[0]*p0+1;
都和dp[0]有关系,而且dp[0]就是我们所求,为常数
设dp[i]=A[i]*dp[0]+B[i];
代入上述方程右边得到:
dp[i]=∑(pk*A[i+k]*dp[0]+pk*B[i+k])+dp[0]*p0+1
=(∑(pk*A[i+k])+p0)dp[0]+∑(pk*B[i+k])+1;
明显A[i]=(∑(pk*A[i+k])+p0)
B[i]=∑(pk*B[i+k])+1
先递推求得A[0]和B[0].
那么 dp[0]=B[0]/(1-A[0]);
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ff first
#define ss second
#define pb push_back
#define ll long long
#define mod 1000000007
#define ull unsigned long long
#define mst(ss,b) memset(ss,b,sizeof(ss));
#define pl(x) cout << #x << "= " << x << endl;
const int inf = 0x3f3f3f3f;
const int N = 1e5+10;
double dp[N];
int n, m;
int path[N], jump[N];
int main(){
while(~scanf("%d%d", &n, &m)){
if(n == 0 && m == 0)break;
mst(dp, 0);
mst(path, -1);
mst(jump, -1);
for(int i=1; i<=m; i++){
int u, v;
scanf("%d%d", &u, &v);
path[u] = v;
}
for(int i=n; i>=1; i--){
int j = path[i];
if(j == -1)continue;
if(jump[j] != -1)jump[i] = jump[j];
else jump[i] = j;
}
for(int i=n-1; i>=0; i--){
if(jump[i] != -1)dp[i] = dp[jump[i]];
else{
for(int j=1; j<=6; j++)
dp[i] += dp[i+j];
dp[i] = dp[i]/6.0+1;
}
}
printf("%.4f\n", dp[0]);
}
return 0;
}
例题2:HDU 4035
dp求期望的题。
题意:
有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树,
从结点1出发,开始走,在每个结点i都有3种可能:
1.被杀死,回到结点1处(概率为ki)
2.找到出口,走出迷宫 (概率为ei)
3.和该点相连有m条边,随机走一条
求:走出迷宫所要走的边数的期望值。
这题是树上的概率dp,上题是有向图,这题是无向图,父子结点的概率互相影响。
设dp[i]表示从i号结点走出迷宫时走过边数的概率,father[i]表示i号结点的父亲结点,child表示i号结点的儿子结点
递推公式求法可参考kuangbin的题解
http://www.cnblogs.com/kuangbin/archive/2012/10/03/2711108.html
#include
using namespace std;
#define ff first
#define ss second
#define pb push_back
#define ll long long
#define mod 1000000007
#define ull unsigned long long
#define mst(ss,b) memset(ss,b,sizeof(ss));
#define dbg(x) cout << #x << "= " << x << endl;
typedef pair <int, int> pii;
const int inf = 0x3f3f3f3f;
const int N = 1e4+5;
const double eps = 1e-12; //这题需要开小点
double k[N], e[N];
vector<int>E[N];
double A[N], B[N], C[N];
int n;
bool dfs(int u, int pre){
int m = E[u].size();
A[u] = k[u];
B[u] = (1-k[u]-e[u])/m;
C[u] = 1-k[u]-e[u];
double tmp = 1.0;
for(int i=0; iint v = E[u][i];
if(v == pre)continue;
if(!dfs(v, u))return 0;
A[u] += (1-k[u]-e[u])/m*A[v];
C[u] += (1-k[u]-e[u])/m*C[v];
tmp -= (1-k[u]-e[u])/m*B[v];
}
if(fabs(tmp) < eps)return 0;
A[u] /= tmp;
B[u] /= tmp;
C[u] /= tmp;
return 1;
}
int main(){
int T;
scanf("%d", &T);
for(int kase=1; kase<=T; kase++){
printf("Case %d: ", kase);
scanf("%d", &n);
for(int i=1; i<=n; i++)E[i].clear();
for(int i=1; iint u, v;
scanf("%d%d", &u, &v);
E[u].pb(v);
E[v].pb(u);
}
for(int i=1; i<=n; i++){
int x, y;
scanf("%d%d", &x, &y);
k[i] = x/100.0;
e[i] = y/100.0;
}
if(dfs(1, -1) && fabs(1-A[1]) > eps)
printf("%.6f\n", C[1]/(1-A[1]));
else puts("impossible");
}
return 0;
}