ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

HDU-5955 Guessing the Dice Roll(AC自动机 + 概率DP + 高斯消元)

2020-07-08 23:07:38  阅读:303  来源: 互联网

标签:Guessing AC int memset tr 高斯消 sizeof include dp


题意:这里有N个玩家在玩一个猜测游戏,每个玩家猜测一个由{1, 2, 3, 4, 5, 6}组成的长度为L的序列,那么一个骰子会被不断地投掷直到猜中一个序列,那么这个人就会赢得游戏。

分析:设\(dp[i][j]\):表示投掷了i个字符,走到AC自动机的第j个位置的概率,可以知道dp[i][j]可以由前面的6个事件转移过来,即\(\frac{1}{6} * (dp[i - 1][a1] + dp[i - 1][a2] + dp[i - 1][a3] + ... + dp[i - 1][a6])\),a1,a2,a3,a4,a5,a6表示前面的投掷数字在AC自动机的位置,当下一个投掷的数字为k时,会从ac自动机的第ai个位置,跳转到第j个位置。因为跳转会回到原先的状态,因此我们可以使用高斯消元解线性方程组。假设g[i]表示AC自动机第j个位置的概率,我们只需要把不同的节点可以跳转这个位置的系数变为1 / 6即可,即如果一个节点为p,那么下一个投掷的数字为q的话,跳转到\(tr[p][q]\),\(令j = tr[p][q]\),就令第j行的第q个位置为1/6,然后我们的每个节点即\(g[i][i] = 1.0\),我们再令根节点\(g[0][0] = 1.0\)即可,记得用G++交。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;
const double eps = 1e-10;
const int N = 10;
const int M = 500005;

int str[N];
int tr[M][10], idx;
int mp[N], has[M];
int q[M], ne[M];
int n, l;

double g[N * 10][N * 10];

void insert(int id)
{
	int p = 0;
	for (int i = 1; i <= l; ++i)
	{
		int t = str[i];
		if (!tr[p][t]) tr[p][t] = ++idx;
		p = tr[p][t];
	}
	has[p] = 1;
	mp[id] = p;
}

void build()
{
	int hh = 0, tt = -1;
	for (int i = 1; i <= 6; ++i)
	{
		if (tr[0][i]) q[++tt] = tr[0][i];
	}

	while (hh <= tt)
	{
		int t = q[hh++];

		for (int i = 1; i <= 6; ++i)
		{
			int p = tr[t][i];

			if (!p) tr[t][i] = tr[ne[t]][i];
			else
			{
				ne[p] = tr[ne[t]][i];
				q[++tt] = p;
			}
		}
	}
}

int gauss()
{
	int c, r;
	int n = idx + 1;
	for (c = 0, r = 0; c < n; ++c)
	{
		int t = r;
		for (int i = r; i < n; ++i)
		{
			if (fabs(g[i][c]) > fabs(g[t][c]))
				t = i;
		}

		if (fabs(g[t][c]) < eps) continue;

		for (int i = c; i <= n; ++i) swap(g[t][i], g[r][i]);
		for (int i = n; i >= c; --i) g[r][i] /= g[r][c];
		for (int i = r + 1; i < n; ++i)
		{
			if (fabs(g[i][c]) > eps)
				for (int j = n; j >= c; --j)
					g[i][j] -= g[r][j] * g[i][c];
		}
		++r;
	}

	if (r < n)
	{
		for (int i = r; i < n; ++i)
			if (fabs(g[i][n]) > eps)
				return 2;
		return 1;
	}

	for (int i = n - 1; i >= 0; --i)
		for (int j = i + 1; j < n; ++j)
			g[i][n] -= g[i][j] * g[j][n];

	return 0;
}

void init()
{
	idx = 0;
	memset(g, 0, sizeof g);
	memset(ne, 0, sizeof ne);
	memset(tr, 0, sizeof tr);
	memset(mp, 0, sizeof mp);
	memset(has, 0, sizeof has);
}

int main()
{
	int t;
	scanf("%d", &t);

	while (t--)
	{		
		scanf("%d%d", &n, &l);

		for (int i = 1; i <= n; ++i)
		{
			for (int j = 1; j <= l; ++j)
				scanf("%d", &str[j]);
			insert(i);
		}
		
		build();

		for (int i = 0; i <= idx; ++i) g[i][i] = -1.0;
		for (int i = 0; i <= idx; ++i)
		{
			if (has[i] == 0)
			{
				for (int j = 1; j <= 6; ++j)
				{
					int p = tr[i][j];
					g[p][i] += 1.0 / 6.0;
				}
			}
		}
		g[0][idx + 1] = -1.0;

		gauss();

		for (int i = 1; i <= n; ++i)
		{
			printf("%.6lf", g[mp[i]][idx + 1]);
			if (i == n) printf("\n");
			else printf(" ");
		}

		init();
	}

	return 0;
}

标签:Guessing,AC,int,memset,tr,高斯消,sizeof,include,dp
来源: https://www.cnblogs.com/pixel-Teee/p/13269798.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有