AC自动机+高斯消元求解线性方程--2016icpc沈阳H

来源:互联网 发布:淘宝天天特价在哪报名 编辑:程序博客网 时间:2024/04/29 11:39

Guessing the Dice Roll


Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
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
35 1123456 21 12 13 14 15 16 14 31 2 32 3 43 4 54 5 6
 

Sample Output
0.200000 0.200000 0.200000 0.2000000.2000000.027778 0.194444 0.194444 0.1944440.194444 0.1944440.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;}


1 0
原创粉丝点击