当前位置: 代码迷 >> 综合 >> 高斯消元法 概率dp 蛇梯棋 Snakes and Ladders LightOJ - 1151 详解
  详细解决方案

高斯消元法 概率dp 蛇梯棋 Snakes and Ladders LightOJ - 1151 详解

热度:0   发布时间:2024-01-28 13:45:18.0

前言:

高斯消元法,用于解方程组

变为矩阵形式

变为对角线上值为1,其余值为0的格式,则后面一列即为对应变量的值(线性代数知识)

具体实现参考这个博客:https://blog.csdn.net/lzyws739307453/article/details/89816311

代码模板:

double a[110][110];
int n=100;
void build()
{构建矩阵
}
double ans[110];void gauss()
{for(int i = 1; i <= n; ++i){int r = i;for(int j = i + 1; j <= n; ++j)if(fabs(a[r][i]) < fabs(a[j][i]))r = j;if(i != r)swap(a[i],a[r]);double div = a[i][i];for(int j = i; j <= n + 1; ++j)a[i][j] /= div;for(int j = i + 1; j <= n; ++j){div = a[j][i];for(int k = i; k <= n + 1; ++k)a[j][k] -= a[i][k] * div;}}ans[n] = a[n][n+1];for(int i = n - 1; i >= 1; --i){ans[i] = a[i][n+1];for(int j = i + 1; j <= n; ++j)ans[i] -= (a[i][j] * ans[j]);}
}

下面看这道题:题目链接

题意:有一个棋盘,棋盘上有梯子和蛇,梯子可从下端直接到上端,蛇也是从蛇头到蛇尾。一个六面骰子,投到几点走几步,求从1到100期望的投骰子次数。

先不考虑蛇和梯子,当我们走到末尾的时候投骰子会有越界情况,所以dp是从后往前推的,越界时呆在原地不动但是投骰子次数要+1

设dp[ i ] 为走到第i 个格子期望次数

没有越界情况:dp [ i ]= ( dp[ i+1 ]+dp[ i+2 ]+dp[ i+3 ]+dp[ i+4 ]+dp[ i+5 ]+dp[ i+6 ]+6)/6;             

有越界情况(i=96):dp [ i ]=(dp[ i+1 ] +dp[ i+2 ]+dp[ i+3 ]+dp[ i+4]+dp[ i ]+dp[ i ]+6)/6;(这里是i =96时的公式,具体dp[ i ]个数根据范围判断)

考虑蛇和梯子 都是从a->b;所以公式为 dp[ a ]=dp[ b ];(本题是从出发点思考的,所以这里的式子也要这样写。)

存在环形(a,b大小不确定),需要高斯消元来解决。

构建二维矩阵,a[110][110]

将所有的未知数移到等号左侧,并将系数写入对应的二维矩阵中,将等号右边的值赋给a[ ] [n+1]

代码

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#define ll long long
using namespace std;
#define inf 0x3f3f3f3f
int n=100;
int book[110];
double a[110][110];
void build()
{for(int i=1; i<n; i++){if(book[i])     //如果该行已有公式continue;for(int k=1; k<=6; k++){if(i+k<=100)a[i][i+k]=(-1.0/6.0);elsea[i][i]-=(1.0/6.0);  //越界}a[i][i]+=1;a[i][n+1]=1;  //等式右边的值}a[n][n]=1,a[n][n+1]=0;
}
double ans[110];void gauss()
{for(int i = 1; i <= n; ++i){int r = i;for(int j = i + 1; j <= n; ++j)if(fabs(a[r][i]) < fabs(a[j][i]))r = j;if(i != r)swap(a[i],a[r]);double div = a[i][i];for(int j = i; j <= n + 1; ++j)a[i][j] /= div;for(int j = i + 1; j <= n; ++j){div = a[j][i];for(int k = i; k <= n + 1; ++k)a[j][k] -= a[i][k] * div;}}ans[n] = a[n][n+1];for(int i = n - 1; i >= 1; --i){ans[i] = a[i][n+1];for(int j = i + 1; j <= n; ++j)ans[i] -= (a[i][j] * ans[j]);}
}
int main()
{int t,q;scanf("%d",&t);int op=0;while(t--){memset(book,0,sizeof(book));memset(a,0,sizeof(a));memset(ans,0,sizeof(ans));scanf("%d",&q);for(int i=0; i<q; i++){int x,y;scanf("%d %d",&x,&y);book[x]=1;a[x][x]=1;a[x][y]=-1;}build();gauss();printf("Case %d: %lf\n",++op,ans[1]);}
}