Hdu 5955 Guessing the Dice Roll 概率DP+高斯消元

Guessing the Dice Roll

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


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
 


n个长度l,由1到6组成的序列,掷骰子,取后l个组成序列,一直到其中一个序列被掷到为止。求每个序列被掷到的概率。


用AC自动机构建状态转移的方式,最多有100种状态。

用A表示转移矩阵,则每一步转移的系数都是1/6.

用P表示答案,X表示原序列概率,则P=(A+A^2+A^3+....+A^n)*X。

因为转移矩阵A收敛,所以A+A^2+A^3+....+A^n=(I-A)^-1

所以(I-A)^-1 * P = X

X=[1.0 0 0 0 0 0....0]

解线性方程组即可解得P


#include <cstdio>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <cmath>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=105,maxk=6,inf=0x3f3f3f3f;  
const ll llinf=0x3f3f3f3f3f3f3f3f;   
const ld pi=acos(-1.0L);
db r[maxn][maxn],ans[maxn];
int b[maxn][maxn];
int num;

struct node{
	struct node *fail;
	struct node *next[maxk];
	int cnt,id,l;
	void init() {
		fail=NULL;
		for (int i=0;i<maxk;i++) next[i]=NULL;
		cnt=l=0;
		id=++num;
	}
};
node *a[maxn],*q[maxn];

void insert(int h,node *root,int len) {
	node *now=root;
	int i;
	for (i=0;i<len;i++) {
		int pos=b[h][i];
		if (now->next[pos]==NULL) {
	    	now->next[pos]=new node;
	    	now->next[pos]->init();
	    	a[num]=now->next[pos];
    	}
    	now=now->next[pos];
	}
	now->cnt++;now->l=h;
}

void buildfail(node *root) {
	node *p=root;
	int front=0,tail=0,i;
	for (i=0;i<maxk;i++) {
		if (p->next[i]!=NULL) {
			p->next[i]->fail=root;
			q[tail++]=p->next[i];
		} else p->next[i]=root;
	}
	while (front<tail) {
		p=q[front];
		for (i=0;i<maxk;i++) {
			if (p->next[i]==NULL) 
			    p->next[i]=p->fail->next[i];
			else {
				node *x=p->fail;
				while (x!=NULL) {
					if (x->next[i]!=NULL) {
						p->next[i]->fail=x->next[i];
						break;
					}
					x=x->fail;
				}
				if (p->fail->next[i]->cnt) p->next[i]->cnt++;
				q[tail++]=p->next[i];
			}
		}
		front++;
	}
}

bool gauss(int size) {  
    int i,j,k;  
    for (i=0;i<size;i++) {  
        k=i;  
        for (j=i+1;j<size;j++) {     //找最大的列主元   
            if (fabs(r[j][i])>fabs(r[k][i])) k=j;  
        }  
 //       if (fabs(r[k][i])<1e-9) return false;    //fail  
        for (j=i;j<=size;j++) 
            swap(r[k][j],r[i][j]);
        db t=r[i][i];
		for (j=i;j<=size;j++) 
            r[i][j]/=t;
        for (j=0;j<size;j++) {  
            if (i==j) continue;  
			db t=r[j][i]; 
            for (k=i;k<=size;k++) {  
                r[j][k]-=t*r[i][k];  
            }  
        }  
    }
//    for (i=size-1;i>=0;i--)
//       r[i][size]=r[i][size]/r[i][i];  
    return true;
}  

int main() {
	int cas;
	scanf("%d",&cas);
	while (cas--) {
		int n,l,i,j,k;
		scanf("%d%d",&n,&l);
		node *root=new node;
		num=-1;
		root->init();
		a[0]=root;
		for (i=1;i<=n;i++) {
			for (j=0;j<l;j++) {
				scanf("%d",&b[i][j]);
				b[i][j]--;
			}
			insert(i,root,l);
		}
		buildfail(root);
		mem0(r);
		for (j=0;j<=num;j++) {
			r[j][j]+=1.0;
			if (a[j]->cnt!=0) continue;
			for (k=0;k<6;k++) 
				r[a[j]->next[k]->id][j]-=1.0/6.0;
		}
		r[0][num+1]=1.0;
		db tot=0.0;
		gauss(num+1);
		for (i=1;i<=num;i++) {
			if (a[i]->cnt!=0) {
				ans[a[i]->l]=r[a[i]->id][num+1];
				tot+=ans[a[i]->l];
			}
		}
		for (i=1;i<=n;i++) {
			printf("%.6lf",ans[i]/tot);
			if (i!=n) printf(" ");
		}
		printf("\n");
	}
	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值