Guessing the Dice Roll
Total Submission(s): 462 Accepted Submission(s): 108
Problem Description
There are N players playing a guessing game. Each player guesses a sequence consists of {1,2,3,4,5,6} with length L, then a dice will be rolled again and again and the roll out sequence will be recorded. The player whose guessing sequence first matches the last L rolls of the dice wins the game.
Input
The first line is the number of test cases. For each test case, the first line contains 2 integers N (1 ≤ N ≤ 10) and L (1 ≤ L ≤ 10). Each of the following N lines contains a guessing sequence with length L. It is guaranteed that the guessing sequences are consist of {1,2,3,4,5,6} and all the guessing sequences are distinct.
Output
For each test case, output a line containing the winning probability of each player with the precision of 6 digits.
Sample Input
3 5 1 1 2 3 4 5 6 2 1 1 2 1 3 1 4 1 5 1 6 1 4 3 1 2 3 2 3 4 3 4 5 4 5 6
Sample Output
0.200000 0.200000 0.200000 0.200000 0.200000 0.027778 0.194444 0.194444 0.194444 0.194444 0.194444 0.285337 0.237781 0.237781 0.239102
问题概述:有n个人每个人先说出一段数子序列(只包含1-6正整数),之后其中一个人不停地roll骰子,当扔出某个
人猜的序列时那个人获胜且游戏结束,求每个人获胜的概率
问题转化:
先建棵字典树并跑AC自动机,这样问题就可以转化为:有一个人初始站在字典树的根上,之后他每roll一次骰
就会根据骰子的点数走到对应的子节点上,如过当前没有子节点,那就会通过失败指针而走到另一个子节点(或
根)上,直到走个某个叶子结束,求每一片叶子会是终点的概率
思路:
对于上面的问题,我们设pxi为那个人走到节点xi上的概率,那么显然pxi = ∑xk*1.0/6,其中xk为所有可以一步
到达xi的点,那么对于每一个节点都可以列出这样的方程,这样就成为了一个线性方程组,那么问题就可以进一步转
化为求解线性方程组,很显然该方程组一定有解且只有一解,跑一下Gauss就好了,最后输出的所有的pxt,其中t为
叶子节点(但是要注意:对于根节点xr,pxr = ∑xk*1.0/6+1,因为初始条件下人就站在根节点!)
这次因为要求解方程组,所以要化成最简矩阵而不单单是阶梯矩阵,最后化出的矩阵应该是这样:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#include<algorithm>
using namespace std;
#define eps 1e-9 /* 用fabs(k)<eps判断浮点数k是否为0 */
int len, k, ans[15];
double Jz[105][105], c[105];
typedef struct
{
int loc, now, root, i, net[1005][7], ed[1005], fail[1005];
void Init()
{
loc = 0;
root = Newnode();
}
int Newnode()
{
loc += 1;
for(i=1;i<=6;i++)
net[loc][i] = -1;
ed[loc] = 0;
return loc;
}
void Update(int a[])
{
now = root;
for(int i=1;i<=len;i++)
{
if(net[now][a[i]]==-1)
net[now][a[i]] = Newnode();
now = net[now][a[i]];
}
ed[now] = -1;
ans[++k] = now;
}
void Create()
{
queue<int> q;
fail[root] = root;
for(i=1;i<=6;i++)
{
if(net[root][i]==-1)
net[root][i] = root;
else
{
fail[net[root][i]] = root;
q.push(net[root][i]);
}
}
while(q.empty()==0)
{
now = q.front();
q.pop();
for(i=1;i<=6;i++)
{
if(net[now][i]==-1)
net[now][i] = net[fail[now]][i];
else
{
fail[net[now][i]] = net[fail[now]][i];
q.push(net[now][i]);
}
}
}
}
}Trie;
Trie AC;
void Gauss(int n, int m);
int main(void)
{
int T, n, i, j, a[15];
scanf("%d", &T);
while(T--)
{
k = 0;
AC.Init();
scanf("%d%d", &n, &len);
for(i=1;i<=n;i++)
{
for(j=1;j<=len;j++)
scanf("%d", &a[j]);
AC.Update(a);
}
AC.Create();
memset(Jz, 0, sizeof(Jz));
for(i=1;i<=AC.loc;i++)
Jz[i][i] = -1;
for(i=1;i<=AC.loc;i++)
{
for(j=1;j<=6;j++)
{
if(AC.net[i][j]!=-1 && AC.ed[i]!=-1)
Jz[AC.net[i][j]][i] += 1.0/6;
}
}
memset(c, 0, sizeof(c));
c[1] = -1;
Gauss(AC.loc, AC.loc);
printf("%f", c[ans[1]]);
for(i=2;i<=n;i++)
printf(" %f", c[ans[i]]);
printf("\n");
}
return 0;
}
void Gauss(int n, int m)
{
int i, j, p, q, r;
p = q = 1;
while(p<=n && q<=m)
{
r = p;
for(i=p+1;i<=n;i++)
if(fabs(Jz[i][q])>fabs(Jz[r][q])) r = i;
/*if(fabs(Jz[r][q])<eps)
return 0; ----方程无解*/
for(i=q;i<=m;i++)
swap(Jz[r][i], Jz[p][i]);
swap(c[r], c[p]);
c[p] /= Jz[p][q];
for(i=q+1;i<=m;i++)
Jz[p][i] /= Jz[p][q];
for(i=1;i<=n;i++)
{
if(Jz[i][q] && i!=p)
{
for(j=q+1;j<=m;j++)
Jz[i][j] -= Jz[p][j]*Jz[i][q];
c[i] -= c[p]*Jz[i][q];
Jz[i][q] = 0;
}
}
q++, p++;
}
//return 1;
}