题目链接:https://cn.vjudge.net/contest/208908#problem/F
题目大意:给你100个方格,编号为1到100,每次你丢一次骰子,决定你下次往前走多少步,有些方格会有一些梯子或者蛇,使得你到该格子时直接转向另一个格子,若你当前的位置+骰子的点数>100,则在原地重新丢一次,问你到编号为100的格子所投骰子次数的期望是多少?
题目解答:我们设dp[i]表示从i走到100的期望次数,我们可以列出以下方程:
但是因为有蛇的存在,所以方程是无序的,不能从后向前递推,但是我们可以考虑将其化为上面所述的100个方程,然后通过高斯消元求解。
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
#define eps 1e-8
double a[105][105];
int nxt[105];
int gaosi(int n,int m)
{
int i,j,row,tmp,col;
for(row=1,col=1;row<=n && col<=m;row++,col++)
{
tmp=row;
for(i=row+1;i<=n;i++)
if(a[i][col]>a[tmp][col])
tmp=i;
if(tmp!=row)
swap(a[row],a[tmp]);
if(fabs(a[row][col])<eps)
{
row--;
continue;
}
for(i=1;i<=n;i++)
{
if(i==row || fabs(a[i][col])<=eps)
continue;
for(j=m;j>=col;j--)
a[i][j]-=a[row][j]/a[row][col]*a[i][col];
}
}
row--;
for(i=row;i>0;i--)
{
for(j=i+1;j<=row;j++)
a[i][m]-=a[i][j]*a[j][m];
a[i][m]/=a[i][i];
}
return row;
}
int main(void)
{
int T,i,j,n,cases=0;
scanf("%d",&T);
while(T--)
{
int x,y;
memset(a,0,sizeof(a));
memset(nxt,0,sizeof(nxt));
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
nxt[x]=y;
}
for(i=1;i<100;i++)
{
if(nxt[i]!=0)
{
a[i][i]=1;
a[i][101]=0;
a[i][nxt[i]]=-1;
}
else
{
int cnt=0;
for(j=1;i+j<=100 && j<=6;j++)
{
cnt++;
a[i][i+j]=-1;
}
a[i][i]=cnt;
a[i][101]=6;
}
}
a[100][100]=1;a[100][101]=0;
gaosi(100,101);
printf("Case %d: %.7f\n",++cases,a[1][101]);
}
return 0;
}