HDU 5966 Guessing the Dice Roll
题意
有 N≤10 个人,每个猜一个长度为L≤10的由1−6构成的序列,保证序列两两不同。
不断地掷骰子,直到后缀与某人的序列匹配,则对应的人获胜。
求每个人获胜的概率。
思路:
建立trie图,跑高斯消元.
高斯消元每个点的意义是:
第i行第j列的值为x 有概率x从点j转移过来
1 const double eps = 1e-9; 2 const int SIGMA_SIZE = 7; 3 const int MAXNODE = 200; 4 5 int ch[MAXNODE][SIGMA_SIZE]; 6 int f[MAXNODE]; 7 int sz; 8 9 void insert(int* P, int len, int v) { 10 int u = 0; 11 for (int i = 0; i < len; i++) { 12 int c = P[i]; 13 if (!ch[u][c]) { 14 memset(ch[sz], 0, sizeof(ch[sz])); 15 ch[u][c] = sz++; 16 } 17 u = ch[u][c]; 18 } 19 } 20 21 void getFail() { 22 f[0] = 0; 23 queue<int> q; 24 for (int c = 1; c < SIGMA_SIZE; c++) { 25 int u = ch[0][c]; 26 if (u) { 27 q.push(u); 28 f[u] = 0; 29 } 30 } 31 while (!q.empty()) { 32 int r = q.front(); q.pop(); 33 for (int c = 1; c < SIGMA_SIZE; c++) { 34 int u = ch[r][c]; 35 if (!u) { 36 ch[r][c] = ch[f[r]][c]; 37 continue; 38 } 39 q.push(u); 40 int v = f[r]; 41 while (v && !ch[v][c]) v = f[v]; 42 f[u] = ch[v][c]; 43 } 44 } 45 } 46 47 //double的高斯消元 48 double a[MAXNODE][MAXNODE], x[MAXNODE];//方程的左边的矩阵和等式右边的值,求解之后x存的就是结果 49 int equ, var;//方程数和未知数个数 50 int Gauss() 51 { 52 for (int k=0, col=0; k<equ && col<var; k++, col++) 53 { 54 int max_r=k; 55 for (int i=k+1; i<equ; i++) 56 if (fabs(a[i][col]) > fabs(a[max_r][col])) max_r=i; 57 if (fabs(a[max_r][col]) < eps) return 0; 58 if (k != max_r) 59 { 60 for (int j = col; j < var; j++) swap(a[k][j], a[max_r][j]); 61 swap(x[k], x[max_r]); 62 } 63 x[k] /= a[k][col]; 64 for (int j=col+1; j<var; j++) a[k][j] /= a[k][col]; 65 a[k][col] = 1; 66 for (int i=0; i<equ; i++) 67 if (i != k) 68 { 69 x[i] -= x[k] * a[i][k]; 70 for(int j=col+1; j<var; j++) a[i][j]-=a[k][j]*a[i][col]; 71 a[i][col] = 0; 72 } 73 } 74 return 1; 75 } 76 77 const int maxn = 20; 78 int n, len; 79 int peo[maxn][maxn]; 80 bool end[MAXNODE]; 81 vector<int> G[MAXNODE]; 82 83 void init() 84 { 85 memset(f, 0, sizeof(f)); 86 memset(ch, 0, sizeof(ch)); 87 memset(a, 0, sizeof(a)); 88 memset(end, 0, sizeof(end)); 89 memset(x, 0, sizeof(x)); 90 91 sz = 1; 92 scanf("%d%d", &n, &len); 93 for (int i = 1; i <= n; i++) 94 { 95 for (int j = 0; j < len; j++) 96 { 97 scanf("%d", &peo[i][j]); 98 } 99 insert(peo[i], len, i); 100 end[sz - 1] = true; 101 } 102 for (int i = 0; i < sz; i++) 103 { 104 G[i].clear(); 105 } 106 } 107 108 void getGraph() 109 { 110 getFail(); 111 for (int i = 0; i < sz; i++) 112 { 113 if (!end[i]) 114 { 115 for (int j = 1; j < 7; j++) 116 { 117 int t = ch[i][j]; 118 G[t].push_back(i); 119 } 120 } 121 } 122 } 123 124 void solve() 125 { 126 getGraph(); 127 equ = var = sz; 128 for (int i = 0; i <sz; i++) 129 { 130 for (auto j : G[i]) 131 { 132 a[i][j] += 1.0/6; 133 } 134 a[i][i] -= 1; 135 } 136 x[0] = -1; 137 138 Gauss(); 139 140 vector<double> ans; 141 for (int i = 0; i < sz; i++) 142 { 143 if (end[i]) 144 { 145 ans.push_back(x[i]); 146 } 147 } 148 for (int i = 0; i < ans.size() - 1; i++) 149 { 150 printf("%.6f ", ans[i]); 151 } 152 printf("%.6f\n", *ans.rbegin()); 153 154 } 155 156 int main() 157 { 158 int T; 159 scanf("%d", &T); 160 while (T--) 161 { 162 init(); 163 solve(); 164 } 165 return 0; 166 }