hdu5955 Guessing the Dice Roll【AC自动机】【高斯消元】【概率】

含高斯消元模板

2016沈阳区域赛http://acm.hdu.edu.cn/showproblem.php?pid=5955

Guessing the Dice Roll

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1632    Accepted Submission(s): 480


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
 
Source
 
Recommend
jiangzijing2015
 
 
 
题意:
有n个人猜掷骰子的序列。给定序列长度是l。只要n个人中的一个序列出现了,这个人就赢了游戏结束。问他们获胜的概率是多少。
思路:
没有想到是AC自动机。但是其实他本质就是在一个自动机的不同状态之间转转转,看最后转到哪个状态上去。
对这几个序列建立了AC自动机之后,就可以列出他们互相之间转移的概率方程了。然后解方程就可以得到每个人获胜的概率。
矩阵中的第(j)行表示的就是关于(j)这个状态的方程。(a[j][i])表示由状态(i)转移到状态(j)的概率。
(a[i][i])本身应该放在方程的右边,所以他是(-1)
根节点是比较特殊的,我们需要再设置一个虚拟节点,虚拟节点到根节点的概率是1,他也应该作为根节点初始时的概率放在右边。
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstdlib>
  5 #include<cstring>
  6 #include<algorithm>
  7 #include<queue>
  8 #include<set>
  9 using namespace std;
 10 typedef long long LL;
 11 #define N 100010
 12 #define pi 3.1415926535
 13 
 14 int n, l, t;
 15 const int maxn = 105;
 16 struct trie{
 17     int son[7];
 18     int ed;
 19     int fail;
 20 }AC[maxn];
 21 int tot = 0;
 22 int fp[11];
 23 
 24 void build(int s[], int id)
 25 {
 26     int now = 0;
 27     for(int i = 0; i < l; i++){
 28         if(AC[now].son[s[i]] == 0){
 29             AC[now].son[s[i]] = ++tot;
 30         }
 31         now = AC[now].son[s[i]];
 32     }
 33     AC[now].ed = id;
 34     fp[id] = now;
 35 }
 36 
 37 void get_fail()
 38 {
 39     queue<int>que;
 40     for(int i = 1; i <= 6; i++){
 41         if(AC[0].son[i] != 0){
 42             AC[AC[0].son[i]].fail = 0;
 43             que.push(AC[0].son[i]);
 44         }
 45     }
 46 
 47     while(!que.empty()){
 48         int u = que.front();
 49         que.pop();
 50         for(int i = 1; i <= 6; i++){
 51             if(AC[u].son[i] != 0){
 52                 AC[AC[u].son[i]].fail = AC[AC[u].fail].son[i];
 53                 que.push(AC[u].son[i]);
 54             }
 55             else{
 56                 AC[u].son[i] = AC[AC[u].fail].son[i];
 57             }
 58         }
 59     }
 60 }
 61 
 62 double a[maxn][maxn], x[maxn];
 63 const double eps = 1e-10;
 64 int equ, var;
 65 void gauss()
 66 {
 67     equ = var = tot + 1;
 68     int i,j,k,col,max_r;
 69     for(k=0,col=0;k<equ&&col<var;k++,col++)
 70     {
 71         max_r=k;
 72         for(i=k+1;i<equ;i++)
 73         {
 74             if(fabs(a[i][col] )>fabs(a[max_r][col] ) ) max_r=i;
 75         }
 76         if(fabs(a[max_r][col])<eps )  return;
 77         if(k!=max_r)
 78         {
 79             for(j=col;j<=var;j++)  swap(a[k][j],a[max_r][j]  );
 80         }
 81         for(j=col+1;j<=var;j++)  a[k][j]/=a[k][col];
 82 
 83         a[k][col]=1;
 84 
 85         for(i=0;i<equ;i++) if(i!=k)
 86         {
 87             for(j=col+1;j<=var;j++) a[i][j]-=a[k][j]*a[i][col];
 88 
 89             a[i][col]=0;
 90         }
 91     }
 92     for(i=0;i<equ;i++)  x[i]=a[i][var];
 93     return;
 94 }
 95 
 96 int main()
 97 {
 98     scanf("%d", &t);
 99     while(t--){
100         for(int i = 0; i <= tot; i++){
101             AC[i].fail = 0;
102             AC[i].ed = 0;
103             for(int j = 0; j < 7; j++){
104                 AC[i].son[j] = 0;
105             }
106         }
107         tot = 0;
108 
109         scanf("%d%d", &n, &l);
110         for(int i = 1; i <= n; i++){
111             int tmp[11];
112             for(int j = 0; j < l; j++){
113                 scanf("%d", &tmp[j]);
114             }
115             build(tmp, i);
116         }
117         get_fail();
118 
119         memset(a, 0, sizeof(a));
120         memset(x, 0, sizeof(x));
121         for(int i = 0; i <= tot; i++)a[i][i] = -1.0;
122         for(int i = 0; i <= tot; i++){
123             if(AC[i].ed == 0){
124                 for(int j = 1; j <= 6; j++){
125                     int to = AC[i].son[j];
126                     a[to][i] += 1.0 / 6;
127                 }
128             }
129 
130         }
131 
132         a[0][tot + 1] = -1.0;//虚拟节点
133         gauss();
134         for(int i = 1; i <= n; i++){
135             printf("%.6f", x[fp[i]]);
136             if(i == n){
137                 printf("
");
138             }
139             else{
140                 printf(" ");
141             }
142         }
143 
144         //cout<<"yes"<<endl;
145     }
146 
147     return 0;
148 }
原文地址:https://www.cnblogs.com/wyboooo/p/9951242.html