题目链接:https://cn.vjudge.net/problem/LightOJ-1151
'Snakes and Ladders' or 'Shap-Ludu' is a game commonly played in Bangladesh. The game is so common that it would be tough to find a person who hasn't played it. But those who haven't played it (unlucky of course!) the rules are as follows.
- There is a 10 x 10 board containing some cells numbered from 1 to 100.
- You start at position 1.
- Each time you throw a perfect dice containing numbers 1 to 6.
- There are some snakes and some ladders in the board. Ladders will take you up from one cell to another. Snakes will take you down.
- If you reach a cell that contains the bottom part of a ladder, you will immediately move to the cell which contains the upper side of that ladder. Similarly if you reach a cell that has a snake-head you immediately go down to the cell where the tail of that snake ends.
- The board is designed so that from any cell you can jump at most once. (For example there is a snake from 62 to 19, assume that another is from 19 to 2. So, if you reach 62, you will first jump to 19, you will jump to 2. These kinds of cases will not be given)
- There is no snake head in the 100-th cell and no ladder (bottom part) in the first cell.
- If you reach cell 100, the game ends. But if you have to go outside the board in any time your move will be lost. That means you will not take that move and you have to throw the dice again.
Now given a board, you have to find the expected number of times you need to throw the dice to win the game. The cases will be given such that a result will be found.
Input
Input starts with an integer T (≤ 105), denoting the number of test cases.
The first line of a case is a blank line. The next line gives you an integer n denoting the number of snakes and ladders. Each of the next n lines contain two integers a and b (1 ≤ a, b ≤ 100, a ≠ b). If a < b, it means that there is a ladder which takes you from a to b. If a > b, it means that there is a snake which takes you from a to b. Assume that the given board follows the above restrictions.
Output
For each case of input, print the case number and the expected number of times you need to throw the dice. Errors less than 10-6 will be ignored.
Sample Input
2
14
4 42
9 30
16 8
14 77
32 12
37 58
47 26
48 73
62 19
70 89
71 67
80 98
87 24
96 76
0
Sample Output
Case 1: 31.54880806
Case 2: 33.0476190476
题目翻译:
"蛇和梯子"或"沙普-卢杜"是孟加拉国常见的游戏。这个游戏太普遍了,很难找到一个没有玩过游戏的人。但是那些没有玩过它的人(当然不是幸运的!
1. 有一个10 x 10板包含一些细胞编号从1到100。
2. 从位置 1 开始。
3. 每次你扔一个包含数字1到6的完美骰子。
4. 黑板上有一些蛇和一些梯子。梯子会把你从一个牢房带到另一个牢房。蛇会把你打倒的
5. 如果到达包含梯子底部的单元格,您将立即移动到包含该梯子上侧的单元格。同样,如果你到达一个有蛇头的细胞,你立即下到蛇的尾巴结束的细胞。
6. 该板的设计,使从任何细胞,你最多可以跳一次。(例如,有一条蛇从62到19,假设另一条是从19到2。所以,如果你达到62岁,你会先跳到19,你会跳到2。不会给出此类案例)
7. 第100个细胞中没有蛇头,第一个细胞没有梯子(底部部分)。
8. 如果你达到100单元格,游戏结束。但是,如果你必须在任何时候走出董事会,你的行动将失去。这意味着你不会采取那个动作,你必须再次掷骰子。
现在给一个板,你必须找到预期的次数,你需要掷骰子赢得比赛。案件将作出这样的结果,以找到结果。
输入
输入以整数 T (= 105)开头,表示测试用例的数量。
案例的第一行是空白行。下一行为您提供一个整数n表示蛇和梯子的数量。接下来的n行中的每一个包含两个整数a和b(1 = a,b = 100,a = b)。如果< b, 则意味着有一个梯子将您从a带到b。如果> b, 则意味着有一条蛇将您从a带到b。假设给定的板遵循上述限制。
输出
对于每个输入案例,打印案例编号和需要掷骰子的预期次数。小于10-6的错误将被忽略。
这个题让我学会了一个新的算法:高斯消元。其实就是以前线代里面学的求矩阵的秩的方法,可以用增广矩阵也可直接求。
关于高斯消元的解释请看我的这篇文章:高斯消元+概率+期望入门总结
下面给出这道题的状态转移方程(来源:网上大佬):
但是这个题不能从后往前直接递推去求,因为可能传到后面也可能传到前面,所以需要用高斯消元直接去解这个100*100的方程。
#include <iostream>
#include<cstring>
#include<cmath>
using namespace std;
const double eps=1e-6;
const int maxn=105;
int nxt[maxn];
double a[maxn][maxn];
void Gauss(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];
}
}
int main(int argc, char** argv) {
int T,n;
scanf("%d",&T);
for(int kcase=1;kcase<=T;kcase++){
memset(nxt,0,sizeof(nxt));
memset(a,0,sizeof(a));
scanf("%d",&n);
for(int i=1;i<=n;++i){
int x,y;
scanf("%d %d",&x,&y);
nxt[x]=y;
}
for(int i=1;i<=100;++i){
if(nxt[i]){
a[i][i]=1;
a[i][nxt[i]]=-1;
a[i][101]=0;
}
else{
int cnt=0;
for(int j=1;j+i<=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;
Gauss(101,101);
printf("Case %d: %.7lf\n",kcase,a[1][101]);
}
return 0;
}
来源:https://blog.csdn.net/qq_43472263/article/details/99675565