hdu 5955 Guessing the Dice Roll 概率DP,ac自动机,高斯消元 ★★


Guessing the Dice Roll

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


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   |   We have carefully selected several similar problems for you:   5981  5980  5979  5978  5977 
 

Statistic |  Submit |  Discuss |  Note


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


问每个人的获胜概率。


先用ac自动机建立好状态关系,再列方程,用高斯消元求解。


列方程:对于每个点x,假设可以转移到点y,那么dp[y]的胜率要加上dp[x]*p[x->y]


对于根节点要注意,相比于其它结点,概率要额外加1。


#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
#define mes(a,x,s)  memset(a,x,(s)*sizeof a[0])
#define mem(a,x)  memset(a,x,sizeof a)
#define ysk(x)  (1<<(x))
typedef long long ll;
typedef pair<int, int> pii;
const int INF =0x3f3f3f3f;
const int maxN= 10,maxL= 10 ,maxNode=101  ;

const double eps=1e-10;
int N,L;
int a[maxN+5][maxL+5];

struct Trie
{
    int ch[200][6],val[200],sz;
    int pos[maxN+5],f[200],last[200];
    void init(){sz=1;mem(ch[0],0);}
    void insert( int ind )
    {
        int x=0;
        for1(i,L)
        {
            int y=a[ind][i];
            if(!ch[x][y])
            {
                mem(ch[sz],0);
                val[sz]=0;
                ch[x][y]=sz++;
            }
            x=ch[x][y];
        }
        val[x]=ind;
        pos[ind]=x;
    }
    void getFail()
    {
        queue<int>q;
        f[0]=0;

        for(int c=0;c<6;c++)
        {
            int y=ch[0][c];
            if(y) {f[y]=0;q.push(y);last[y]=0;}

        }
        while(!q.empty())
        {
            int x=q.front();q.pop();
            for(int c=0;c<6;c++)
            {
                int y=ch[x][c];
                if(!y) {ch[x][c]=ch[f[x]][c];continue;  }
                q.push(y);
                int v=f[x];
                while(v&&!ch[v][c]) v=f[v];
                f[y]=ch[v][c];

                last[y]=val[f[y]]?f[y]:last[f[y]];
            }
        }

    }

}trie;

struct Guass
{
    int equ,var;
    double a[maxNode+20][maxNode+20],x[maxNode+20];
    void init()
    {
        mem(a,0);
    }
    void build()
    {
       int sz=trie.sz;
       equ=var=sz;

       for0(i,sz)
       {
           a[i][i]=-1;
       }
       a[0][var]=-1;

       for0(i,sz) if(!trie.val[i])
       {
           for0(j,6)
           {
               int y=trie.ch[i][j];
               a[y][i]+=1.0/6;
           }
       }
    }
    int elimination()
    {
        int i,j,k,col,max_r;
        for(k=0,col=0;k<equ&&col<var;k++,col++)
        {
            max_r=k;
            for(i=k+1;i<equ;i++)
            {
                if(fabs(a[i][col] )>fabs(a[max_r][col] ) ) max_r=i;
            }
            if(fabs(a[max_r][col])<eps )  return 0;
            if(k!=max_r)
            {
                for(j=col;j<=var;j++)  swap(a[k][j],a[max_r][j]  );
            }
            for(j=col+1;j<=var;j++)  a[k][j]/=a[k][col];

            a[k][col]=1;

            for(i=0;i<equ;i++) if(i!=k)
            {
                for(j=col+1;j<=var;j++) a[i][j]-=a[k][j]*a[i][col];

                a[i][col]=0;
            }
        }
        for(i=0;i<equ;i++)  x[i]=a[i][var];
        return 1;
    }
}guass;
int main()
{
   std::ios::sync_with_stdio(false);
   int T;cin>>T;
   while(T--)
   {
       cin>>N>>L;
       for1(i,N) for1(j,L)
       {
           cin>>a[i][j];
           a[i][j]--;
       }

       trie.init();
       for1(i,N)   trie.insert(i);

       trie.getFail();

       guass.init();
       guass.build();
       guass.elimination();

       for1(i,N)
       {
            int p=trie.pos[i];
            printf("%.6f%c",guass.x[p],i==N?'\n':' ');
       }







   }
   return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值