LightOJ - 1151 Snakes and Ladders(概率dp+高斯消元)
有100个格子,从1开始走,每次抛骰子走1~6,若抛出的点数导致走出了100以外,则重新抛一次。有n个格子会单向传送到其他格子,G[i]表示从i传送到G[i]。
1和100不会有传送,一个格子也不会有两种传送。问走到100的期望值。
我们不难推出方程 但是由于dp值之间的前后影响 我们需要用高斯消元来解决
#include <bits/stdc++.h> #define ll long long #define inf 0x3f3f3f3f using namespace std; const int N = 1e5+7; const double eps = 1e-8; int G[107]; double A[207][107],x[107];//A矩阵中每一行1~n存系数,n+1为答案,m个方程m行,x是最终的答案 //注意空间要多开几个,还要考虑n,m不同的情况 int Guass(int n,int m)//有n个未知数,m个方程 { int i=1,j=1,k,r,c; while(i<=m && j<=n)//正在处理第i个方程,解第j个未知数 { r=i;//找到绝对值最大的系数,防止除数为0的情况,使得其他方程组系数不会变得太大 for(k=i+1;k<=m;k++)if(fabs(A[k][j])>fabs(A[r][j]))r=k; if(fabs(A[r][j])>=eps)//出现为0的情况,说明此项已经被消掉了,直接用进行下一个未知数,而方程不变,不过这个时候,一般来说跳过的这个元素就没有固定解啦 { for(c=1;c<=n+1;c++)swap(A[i][c],A[r][c]);//交换 for(k=i+1;k<=m;k++)if(fabs(A[k][j])>=eps) { double f=A[k][j]/A[i][j]; for(c=j;c<=n+1;c++)//当前方程j前面的系数都是0 A[k][c]-=f*A[i][c]; } i++;//获取下一个方程 } j++;//去消下一个未知数 } //必须先判无解再判断多解 for(k=i;k<=m;k++)if(fabs(A[k][n+1])>=eps)return 0;//若有一行系数为0但是不为答案,则无解 if(i<=n)return 2;//如果被你处理出来的方程没有n个,就会出现多解。(i=n表示解决了n-1个方程) for(int i=n;i>=1;i--) { for(j=i+1;j<=n;j++) A[i][n+1]-=A[i][j]*x[j]; x[i]=A[i][n+1]/A[i][i]; } //最终统计出来的答案x[i]肯定是对应的第i个元素的解哦,换的只是方程的顺序 return 1;//拥有唯一解 } int main(){ // ios::sync_with_stdio(false); // cin.tie(0); int t; scanf("%d",&t); int w=0; while(t--){ memset(G,0,sizeof(G)); memset(A,0,sizeof(A)); memset(x,0,sizeof(x)); int n; scanf("%d",&n); for(int i=1;i<=n;i++){ int a,b; scanf("%d%d",&a,&b); G[a]=b; } A[100][100]=1; A[100][101]=0; for(int i=1;i<=99;i++){ if(G[i]){ A[i][i]=1; A[i][G[i]]=-1; A[i][101]=0; }else{ int top=min(6,100-i); for(int j=1;j<=top;j++){ A[i][i+j]=-1; } A[i][i]=top; A[i][101]=6; } } Guass(100,101); printf("Case %d: %.10f\n",++w,x[1]); } }