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

变为矩阵形式

变为对角线上值为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);
else
a[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]);
}
}

287

被折叠的 条评论
为什么被折叠?



