您的位置:首页 > 其它

hdu 5955 (ac自动机+高斯消元 )

2017-04-05 21:31 357 查看
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.

题意:掷骰子,n个人,每人预测一个长度为L的序列,直至筛子序列的最后L个数与某个人预测的一致为止游戏结束(每个人预测的序列不一样,且长度均为L)。问每个人的获胜概率。

tip:

首先这种概率题会想到列等式高斯消元,但是状态是如何转移的呢,一个点能做到哪些点呢。。建立ac自动机,每个节点的转移是fail,除了尾巴节点不转移,其他的都是一样的。。。然后0节点的概率为1 其他的点I的概率是转移到他的点j的概率*p(j,i),方程就列出来了

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <cmath>
using namespace std;
const int maxn = 110;
int n,l,node,ch[maxn][7],s[11],pos[11];
int fail[maxn],val[maxn];
double G[maxn][maxn],B[maxn],x[maxn],ans[11];

void Insert(int per){//pos[per] = node;
int tmp = 0;
for(int i = 0 ; i < l; i++){
int pos = s[i];
if(ch[tmp][pos] == 0){
val[node] = 0;
memset(ch[node],0,sizeof(ch[node]));
ch[tmp][pos] = node++;
}
tmp = ch[tmp][pos];
}
val[tmp] = per;
pos[per] = tmp;
}

void init(){
node = 1;
scanf("%d%d",&n,&l);
memset(G,0,sizeof(G));
for(int i = 0 ; i < maxn; i++)
pos[i] = B[i] = ch[0][i] =x[i]= 0;
for(int i = 1 ; i <= n ; i++){
for(int j = 0 ; j < l ; j++)
scanf("%d",&s[j]);
Insert(i);
}

}

void getfail(){
queue<int> q;
for(int i = 1 ; i <= 6 ;i++){
if(ch[0][i] != 0){
q.push(ch[0][i]);
fail[ch[0][i]] = 0;
}
}

while(!q.empty()){
int tmp = q.front();
q.pop();
for(int i = 1; i <= 6 ;i++){
if(ch[tmp][i]!=0){
q.push(ch[tmp][i]);
int v = fail[tmp];
while(v && ch[v][i]== 0)  v = fail[v];
fail[ch[tmp][i]] = ch[v][i];
}
}
}
}

void pp(){
for(int i = 0 ; i < node ;i++){
for(int j = 0 ; j < node; j++)
printf("%lf ",G[i][j]);
cout <<endl;
}
}

void make_matrix(){
for(int i =  0 ; i < node ;i++) G[i][i] -= 1;
B[0] = -1;
for(int i = 0 ; i < node; i++){
for(int j = 1; j <= 6 ; j++){
// printf("i = [ %d ] j = [%d] \n",i,j);
if(val[i] == 0){
// cout <<"yes"<<endl;
if(ch[i][j])    G[ch[i][j]][i] += 1.0/6;
else{
int v = fail[i];
while(v && ch[v][j] == 0)   v = fail[v];
G[ch[v][j]][i] += 1.0/6;
//cout << ch[v][j]<<"   "<<i <<"  " <<G[ch[v][j]][i]<<endl;
}
}
}
}
// pp();
}

void Guass(){
for(int i = 0 ; i < node ;i++){
int i0=  i;
for(int j = i ; j < node ;j++)
if(G[j][i] != 0.0 && fabs(G[j][i]) >= fabs(G[i0][i])){
i0 = j;
}

for(int k =  i ; k < node ;k++)
swap(G[i][k],G[i0][k]);
swap(B[i],B[i0]);
for(int j = i+1 ; j< node; j++){
double tmp = G[j][i]/G[i][i];
for(int k =  i ; k < node; k++){
G[j][k] -= G[i][k] * tmp;
}
B[j] -= B[i]*tmp;
}
}
for(int i = node-1; i >= 0 ; i--){
x[i] = B[i]/G[i][i];
for(int j = 0; j < i ; j++){
B[j] -= G[j][i] * x[i];
}
//cout <<"x = "<<x[i]<<endl;
}
}

void print(){
for(int i = 1 ; i <= n; i++){
ans[i] = x[pos[i]];
}
for(int i =  1; i <= n ; i++){
printf("%.6f%c",ans[i],i==n?'\n':' ');
}
}

int main(){
int T;
scanf("%d",&T);
for(int i = 1; i <= T ; i++){
init();//cout <<"val = "<<val[2]<<endl;
getfail();
make_matrix();
Guass();
print();
}
}
/*
10
5 9
1 3 2 5 1 2 3 2 3
1 2 2 4 3 1 4 5 2
1 5 2 3 2 1 4 2 1
1 2 4 2 2 3 2 3 2
1 5 1 2 3 1 3 2 3
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息