2016icpc瀋陽 HDU 5955 Guessing the Dice Roll AC自動機 高斯消元

題意: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;
}

用高斯消元求解狀態矩陣的穩態解

發佈了21 篇原創文章 · 獲贊 0 · 訪問量 3292
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章