題意:n個人每人一個長爲L的只包含1-6的猜測序列,一直擲骰子直到結果出現某個人的猜測序列,該人獲勝,求每人獲勝概率
題解:隨機過程裏的馬爾可夫過程的穩定狀態,在AC自動機上做狀態轉移,
#include <iostream>
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <set>
#include <stack>
#include <sstream>
#include <queue>
#include <map>
#include <functional>
#include <bitset>
#include <ctime>
using namespace std;
#define pb push_back
#define mk make_pair
#define ll long long
#define ull unsigned long long
#define pii pair<int, int>
#define mk make_pair
#define fi first
#define se second
#define ALL(A) A.begin(), A.end()
#define rep(i,n) for(int (i)=0;(i)<(int)(n);(i)++)
#define repr(i, n) for(int (i)=(int)(n);(i)>=0;(i)--)
#define repab(i,a,b) for(int (i)=(int)(a);(i)<=(int)(b);(i)++)
#define reprab(i,a,b) for(int (i)=(int)(a);(i)>=(int)(b);(i)--)
#define sc(x) scanf("%d", &x)
#define pr(x) printf("x:%d\n", x)
#define fastio ios::sync_with_stdio(0), cin.tie(0)
#define frein freopen("in.txt", "r", stdin)
#define freout freopen("out.txt", "w", stdout)
#define freout1 freopen("out1.txt", "w", stdout)
#define lb puts("")
#define lson ((rt<<1)+1)
#define rson ((rt<<1)+2)
#define mid ((l+r)/2)
#define lmid (l+(r-l)/3)
#define rmid (r-(r-l)/3)
#define debug cout<<"???"<<endl
const double PI = 3.1415926535897932384626433;
const ll mod = 2147493647;
const int INF = 0x3f3f3f3f;
const double eps = 1e-12;
template<class T> T gcd(T a, T b){if(!b)return a;return gcd(b,a%b);}
const int maxn = 120, sgm_sz = 6;
struct Trie
{
int ch[maxn][sgm_sz];
int val[maxn];
int last[maxn];
int f[maxn];
int val_id[maxn];
int sz;
void init()
{
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
memset(val_id, 0, sizeof(val_id));
}
int idx(char c) {return c - '1';}
void Insert(char *s, int v)
{
int u = 0, len = strlen(s);
for(int i = 0; i < len; i++){
int c = idx(s[i]);
if(!ch[u][c]){
memset(ch[sz], 0, sizeof(ch[sz]));
ch[u][c] = sz;
val[sz++] = 0;
}
u = ch[u][c];
}
val[u] = v;
val_id[v] = u;
}
void getFail()
{
queue<int> q;
last[0] = f[0] = 0;
for(int i = 0; i < sgm_sz; i++){
int u = ch[0][i];
if(u){
f[u] = last[u] = 0;
q.push(u);
}
}
while(!q.empty()){
int p = q.front(); q.pop();
for(int i = 0; i < sgm_sz; i++){
int u = ch[p][i];
if(!u){
ch[p][i] = ch[f[p]][i];
continue;
}
q.push(u);
int v = f[p];
while(v && !ch[v][i]) v = f[v];
f[u] = ch[v][i];
last[u] = val[f[u]] ? f[u] : last[f[u]];
}
}
}
/*void find(char *s)
{
int len = strlen(s), u = 0;
for(int i = 0; i < len; i++){
int c = idx(s[i]);
u = ch[u][c];
if(val[u]) deal(u);
else if(last[u]) deal(last[u]);
}
}
void deal(int u)
{
if(u){
//TODO
deal(last[u]);
}
}*/
} ac;
double a[maxn][maxn];
int equ,var;//equ個方程,var個變量
double x[maxn];//解集
bool free_x[maxn];
int n;
int sgn(double x)
{
return (x>eps)-(x<-eps);
}
void print_a()
{
for(int i = 0; i < equ; i++){
for(int j = 0; j <= var; j++){
printf("%.6f ", a[i][j]);
}lb;
}
}
void print_x()
{
for(int i = 0; i < var; i++){
printf("x[%d]:%.6f\n",i,x[i]);
}
}
void gauss_build(int equ_par, int var_par)
{
memset(a, 0, sizeof(a));
memset(x, 0, sizeof(x));
equ = equ_par;
var = var_par;
auto val = ac.val;
auto ch = ac.ch;
int sz = ac.sz;
for(int i = 0; i < sz; i++){
a[i][i] += -1;
if(val[i]) continue;
for(int j = 0; j < sgm_sz; j++){
a[ch[i][j]][i] += 1.0/6;
}
}
a[0][var] += -1.0;
}
// 高斯消元法解方程組(Gauss-Jordan elimination).(0表示無解,1表示唯一解,大於1表示無窮解,並返回自由變元的個數)
int gauss()
{
//多少個方程,多少個變量
int i,j,k;
int max_r; // 當前這列絕對值最大的行.
int col; // 當前處理的列.
double temp;
int free_x_num;
int free_index;
// 轉換爲階梯陣.
col = 0; // 當前處理的列.
memset(free_x,true,sizeof(free_x));
for(k = 0; k<equ && col<var; k++, col++){
max_r = k;
for(i = k+1; i < equ; i++){
if(sgn(fabs(a[i][col]) - fabs(a[max_r][col]))>0)
max_r = i;
}
if(max_r != k){ // 與第k行交換.
for(j = k; j < var+1; j++)
swap(a[k][j], a[max_r][j]);
}
if(sgn(a[k][col]) == 0){ // 說明該col列第k行以下全是0了,則處理當前行的下一列.
k--; continue;
}
for(i = k+1; i < equ; i++){ // 枚舉要刪去的行.
if (sgn(a[i][col]) != 0){
temp = a[i][col]/a[k][col];
for(j = col; j < var+1; j++){
a[i][j] = a[i][j] - a[k][j]*temp;
}
}
}
}
for(i = k; i < equ; i++){
if(sgn(a[i][col]) != 0)
return 0;
}
if(k < var){
for(i = k-1; i >= 0; i--){
free_x_num = 0;
for(j = 0; j < var; j++){
if(sgn(a[i][j]) != 0 && free_x[j])
free_x_num++,free_index=j;
}
if(free_x_num > 1) continue;
temp = a[i][var];
for(j = 0; j < var; j++){
if(sgn(a[i][j])!=0 && j!=free_index)
temp -= a[i][j]*x[j];
}
x[free_index] = temp/a[i][free_index];
free_x[free_index] = 0;
}
return var-k;
}
for (i = var-1; i >= 0; i--){
temp = a[i][var];
for(j = i+1; j <var; j++){
if(sgn(a[i][j]) != 0)
temp -= a[i][j]*x[j];
}
x[i] = temp/a[i][i];
}
return 1;
}
int main()
{
//frein;
//freout;
int n,t,l;
sc(t);
while(t--){
ac.init();
sc(n); sc(l);
char s[15];
for(int i = 1; i <= n; i++){
for(int j = 0; j < l; j++){
int k; sc(k);
s[j] = '0'+k;
}
s[l] = '\0';
ac.Insert(s, i);
}
ac.getFail();
gauss_build(ac.sz, ac.sz);
//print_a();
gauss();
//print_x();
for(int i = 1; i <= n; i++){
//printf("val_id[%d]:%d\n",i,ac.val_id[i]);
printf("%.6f%c", x[ac.val_id[i]], (i==n)?'\n':' ');
}
}
return 0;
}
用高斯消元求解狀態矩陣的穩態解