首先来个期望的论文,讲的非常好,里面也提到了使用线性方程组求解,尤其适用于有向图的期望问题。
http://www.lightoj.com/volume_showproblem.php?problem=1151
题意:有个1~100个格子的地图,每次投骰子,点数1~6,问到达第100格所需的投骰子次数期望值是多少,注意如果最后走的点数超出了地图,不算完成。地图中有传送门,a b表示从第a格可以到b格。
思路:首先可以想到DP的转移有两种,如果i是传送门那么\(dp[i] = dp[tp[i]] \),如果不是,则\(dp[i]=\frac{6+\sum_{j = 1}^{6}{dp[i+j]}}{6}\) 由于传送门可能成环,那么路径有无数条,所以需要转换成方程\(6 * dp[i] - \sum_{j = 1}^{6}{dp[i+j]} = 6 \) ,\(dp[i] - dp[tp[i]] = 0 \)
再用高斯消元求解。
高斯消元的模板网上找的..
/** @Date : 2016-12-03-20.06
* @Author : Lweleth (SoungEarlf@gmail.com)
* @Link : https://github.com/
* @Version :
*/
#include<bits/stdc++.h>
#define LL long long
#define PII pair
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1e5+2000;
const double eps = 1e-12;
int tp[110];
double mat[110][110];
double x[110];
int free_x[110];
int Gauss(int equ, int var)
{
int k;
int max_r;
int col;
int ta, tb;
int LCM;
int temp;
int free_idx, free_num;
memset(free_x, 1, sizeof(free_x));
MMF(x);
for(k = col = 0; k < equ && col < var; k++, col++)
{
max_r = k;
for(int i = k + 1; i < equ; i++)
if(fabs(mat[i][col]) - fabs(mat[max_r][col]) > eps)
max_r = i;
if(max_r != k)
for(int j = k; j < var + 1; j++)
swap(mat[max_r][j], mat[k][j]);
if(fabs(mat[k][col]) <= eps)
{
k--;
continue;
}
for(int i = k + 1; i < equ; i++)
{
if(fabs(mat[i][col]) <= eps)
continue;
double tt = mat[i][col] / mat[k][col];
for(int j = col; j < var + 1; j++)
mat[i][j] -= mat[k][j] * tt;
}
}
//no solution
for(int i = k; i <= equ; i++)
if(fabs(mat[i][var]) > eps)
return -1;
//multiple
if(k < var)
{
for(int i = k - 1; i >= 0; i--)
{
free_num = 0;
for(int j = 0; j < var; j++)
if(fabs(mat[i][j]) > eps && free_x[j])
{
free_num++;
free_idx = j;
}
if(free_num > 1)//multiple var, and can't solve
continue;
double tt = mat[i][var];
for(int j = 0; j < var; j++)
if(j != free_num && fabs(mat[i][j]) > eps)
tt -= mat[i][j] * x[j];
free_x[free_idx] = 0;
x[free_idx] = tt / mat[i][free_idx];
}
return var - k;
}
//only one
for(int i = var - 1; i >= 0; i--)
{
double tt = mat[i][var];
for(int j = i + 1; j < var; j++)
if(fabs(mat[i][j]) > eps)
tt -= mat[i][j] * x[j];
x[i] = tt / mat[i][i];
}
return 1;
}
int main()
{
int T;
int cnt = 0;
cin >> T;
while(T--)
{
int n;
scanf("%d", &n);
for(int i = 1; i <= 100; i++)
{
tp[i] = i;
}
int a, b;
for(int i = 1; i <= n; i++)
scanf("%d%d", &a, &b), tp[a] = b;
MMF(mat);
mat[100][100] = 1;
mat[100][101] = 0;
for(int i = 1; i < 100; i++)
{
if(tp[i] != i)
{
mat[i][i] = 1;
mat[i][tp[i]] = -1;
mat[i][101] = 0;
}
else
{
int k = 0;
for(int j = 1; j <= 6; j++)
if(j + i <= 100)
{
k++;
mat[i][i + j] = -1;
}
mat[i][i] = k;
mat[i][101] = 6;
}
}
Gauss(101, 101);
printf("Case %d: %.10lf\n", ++cnt, x[1]);
}
return 0;
}