植物大战僵尸算个out的游戏了,原谅被出题逼疯了的跑来挖坟了。
会玩的请无视这一段直接看题目{
游戏中僵尸向你的房子进发,吃掉沿途遇到的植物进入你的房子 你就死翘了
你在土地上种植各种植物来攻击阻挡僵尸
手推车:放置在终点,僵尸走到面前会启动推倒一整行的僵尸
大蒜:可种植的一种植物,发出恶心的气味,僵尸咬了一口就会换到邻近的另一行(如果有相邻两行,那么移动到另外两行概率是相等的)
南瓜:单纯的肉盾 被僵尸啃的
耐久度K: 植物被咬了K口后被僵尸吃掉
如有其他对游戏的不理解请clarify
}
问题是这样的:
我们的院子变成了N行M列的,而且种满了大蒜(耐久度K)(图是我盗了 我不会这么无聊的)coming的僵尸只有一只(然而这只僵尸貌似发生了变异,它每啃一口植物,同一列相同种类的植物也被啃掉一口,一口一排的样子恩恩),初始位置在第S行,因为没有放置攻击性的植物,所以僵尸就一路吃了,于是出题者很想知道僵尸死在自上而下1-N号手推车的概率各是多少
(无视掉图中的南瓜,实际上对僵尸行走没有影响。。)
一个整数T(表示T组数据)
接下来的T组数据
每组给定四个整数 N M K S
数据范围
T<=1000
0<N<=20
0<M<=1000
0<K<=1000
1<=S<=N
对于每组数据输出一行N个4位小数 用空格隔开 表示僵尸死在相应行的概率 行末没有空格
1 5 9 5 3
0.0000 0.5000 0.0000 0.5000 0.0000
#include<bits/stdc++.h> using namespace std; int n,m,k,s; struct Matrix{ double a[25][25]; void init(){ memset(a,0,sizeof(a)); } void unit(){ for(int i=1;i<=n;i++){ a[i][i]=1.0000; } } Matrix operator * (Matrix &X)const { Matrix ret; ret.init(); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ ret.a[i][j]=0.0; for(int k=1;k<=n;k++){ ret.a[i][j]+= X.a[i][k] * a[k][j]; } } } return ret; } }A,B; void debug(){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++) printf("%.3lf ",B.a[i][j]); printf("\n"); } } Matrix &POW(Matrix &tB,int x){ while(x){ if(x&1){ tB=tB*A; } x>>=1; A=A*A; } return tB; } int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d%d%d%d",&n,&m,&k,&s); if(n==1){ printf("1.0000\n"); continue; }else{ A.init(); for(int i=1;i<=n;i++){ if(i==1){ A.a[i][2]=1.0; }else if(i==n){ A.a[i][n-1]=1.0; }else { A.a[i][i+1]=A.a[i][i-1]=0.5; } } B.init(); B.unit(); // debug(); POW(B,m*k); for(int i=1;i<=n;i++){ printf("%.4lf%c",B.a[s][i],i==n?'\n':' '); } } } return 0; }
图文详解:
假设以n,m,k,s分别为5,9,9,3为例。P、PP、PPP分别代表咬1、2、3口后的概率,只是对于耐久度为9时,他们是在同一列的,只不过为了表示,所以这样给出,不要误解。PP1=0* P1+0.5* P2+0* P3+0* P4+ 0 * P5
PP2=1* P1+0 * P2+0.5*P3+0* P4+0* P5
PP3=0* P1+0.5* P2+0* P3+0.5*P4+0* P5
PP4=0* P1+0* P2+0.5* P3+0* P4+1* P5
PP5=0* P1+0* P2+0* P3+0.5*P4+0* P5
由上表可以看出,后一个列概率矩阵PP由前一个概率矩阵P乘以某一个矩阵得到。我们假设该某矩阵为A即:
0 |
1 |
0 |
0 |
0 |
0.5 |
0 |
0.5 |
0 |
0 |
0 |
0.5 |
0 |
0.5 |
0 |
0 |
0 |
0.5 |
0 |
0.5 |
0 |
0 |
0 |
1 |
0 |
P1 |
P2 |
P3 |
P4 |
P5 |
用B*A得到下一个行概率矩阵B‘。同时由于矩相乘具有结合律,所以我们可以用矩阵快速幂来先求出转移n次的转移矩阵An*k,然后用原始矩阵B*An*k即可求得。由于原始矩阵B只有第s列为1,所以只需最后将矩阵的s行1---n列顺序输出即为答案。