1. 程式人生 > >bzoj1444[Jsoi2009]有趣的遊戲[AC自動機]

bzoj1444[Jsoi2009]有趣的遊戲[AC自動機]

cstring () pro end names bzoj 學習 http cpp

題面

bzoj

我要向師父學習善待每一只數據結構
考慮成環,那麽高斯消元
然鵝這道題太小了 所以直接轉移矩陣自乘就好啦
終點不向外連邊 有一條向自己的,概率為一的自環來作為結尾
對於其他店 若有邊\((u -> v) = p\) 那麽mat[u][v] += p


#include <cmath>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <complex>
#include <ctime>
#include <vector>
#include <queue>
#include <bitset>
#define mp(x, y) make_pair(x, y)
using namespace std;
const int N = 15;
const int M = 105;
int n, m, len, sz, en[N];
double p[N];
struct Matrix{
    double w[M][M];
    void clear(){
        for(int i = 0; i <= sz; ++i)
             for(int j = 0; j <= sz; ++j)
                 w[i][j] = 0;
    }
    void print(){
        printf("--------------------\n");
        for(int i = 0; i <= sz; ++i){
             for(int j = 0; j <= sz; ++j)
                 printf("%.2lf ", w[i][j]);
            printf("\n");
        }
        printf("--------------------\n");
    }
    friend Matrix operator *(const Matrix x, const Matrix y){
        Matrix z; z.clear();
        for(int i = 0; i <= sz; ++i)
            for(int j = 0; j <= sz; ++j)
                for(int k = 0; k <= sz; ++k)
                    z.w[i][j] += x.w[i][k] * y.w[k][j];
    //  z.print();
        return z;
    }
}mat, res; 
struct AC{
    int ch[M][N], f[M];
    bool flag[M];
    queue<int> que;
    void ins(char* str, int id){
        int now = 0;
        for(int i = 1, cc; i <= len; ++i){
            cc = str[i] - 'A';
            if(!ch[now][cc]) ch[now][cc] = ++sz;
            now = ch[now][cc];
        }
        en[id] = now, flag[now] = 1;
    }
    void build(){
        int now = 0;
        for(int i = 0; i < m; ++i) if(ch[0][i]) que.push(ch[0][i]);
        while(!que.empty()){
            int fro = que.front(); que.pop();
            for(int i = 0; i < m; ++i){
                if(ch[fro][i]) f[ch[fro][i]] = ch[f[fro]][i], que.push(ch[fro][i]);//!!
                else ch[fro][i] = ch[f[fro]][i];
            }
        }
        mat.clear();
        for(int i = 0; i <= sz; ++i){
            if(flag[i]){
                mat.w[i][i] = 1; continue;
            }
            for(int j = 0; j < m; ++j){
                mat.w[i][ch[i][j]] += p[j];
            }
        }  
    }
}ac;


int main(){
    scanf("%d%d%d", &n, &len, &m);
    for(int i = 0; i < m; ++i){
        double x, y; scanf("%lf%lf", &x, &y);
        p[i] = x / y;
    }
    char str[N];
    for(int i = 1; i <= n; ++i){
        scanf("%s", str + 1);
        ac.ins(str, i);
    }
    ac.build();
    for(int i = 1; i <= 100; ++i) mat = mat * mat;
    //轉移矩陣自乘 得到來自0的解 
    for(int i = 1; i <= n; ++i) printf("%.2lf\n", mat.w[0][en[i]]); 
    return 0;   
}

bzoj1444[Jsoi2009]有趣的遊戲[AC自動機]