HDU 5955 Guessing the Dice Roll AC自动机 高斯消元

这题把AC自动机模板和高斯消元的经典题拼在了一起。

AC自动机请转HDU 2222。

高斯消元原型题请参考《挑战程序设计竞赛》第二版 288 页的 Random Walk。

有了这两题的基础之后,这一题只是把 Random Walk 题中的网格图转到了AC自动机的状态表里。

我们先将每个人的猜测序列建成AC自动机。对于AC自动机里的每个状态,如果该状态不是结束状态,则下一个骰子扔出1~6的时候,该状态的概率都会有1/6贡献到S(now, i)里,now表示该状态,S(i, j)表示状态i扔出j时转移到的下一个状态。初始化的时候,AC自动机节点0(即总的根节点)概率为1。这样生成一个sz行sz+1列的增广矩阵之后,拿高斯消元求解最右边一列的答案即可。

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
const int maxn=105;
int T,n,L,a[15],id[maxn];
struct Aho {
    struct state {
        int next[6],tag,fail;
    } stateTable[maxn];
    int size;
    void init() {
        memset(stateTable,0,sizeof stateTable);
        size=0;
    }
    void insert(int *a,int x) {
        int now=0;
        for (int i=0;i<L;++i) {
            if (!stateTable[now].next[a[i]-1])
                stateTable[now].next[a[i]-1]=++size;
            now=stateTable[now].next[a[i]-1];
        }
        stateTable[now].tag=1;
        id[x]=now;
    }
    void build() {
        queue<int> que;
        stateTable[0].fail=-1;
        for (int i=0;i<6;++i)
            if (stateTable[0].next[i]) {
                stateTable[stateTable[0].next[i]].fail=0;
                que.push(stateTable[0].next[i]);
            }
        while (!que.empty()) {
            int now=que.front();
            que.pop();
            for (int i=0;i<6;++i) {
                int o=stateTable[now].next[i];
                if (o) {
                    int v=stateTable[now].fail;
                    while (v!=-1) {
                        if (stateTable[v].next[i]) {
                            stateTable[o].fail=stateTable[v].next[i];
                            break;
                        }
                        v=stateTable[v].fail;
                    }
                    if (v==-1)
                        stateTable[o].fail=0;
                    que.push(o);
                }
            }
        }
    }
    int getnext(int i,int j) {
        int v=stateTable[i].next[j];
        if (!v) {
            int o=stateTable[i].fail;
            while (o!=-1) {
                if (stateTable[o].next[j])
                    return stateTable[o].next[j];
                o=stateTable[o].fail;
            }
        }
        return v;
    }
    void print() {
        for (int i=0;i<=size;++i) {
            printf("node %d: ",i);
            for (int j=0;j<6;++j) {
                int o=stateTable[i].next[j];
                if (o) printf("(node #%d: val=%d tag=%d fail=%d) ",o,j+1,stateTable[o].tag,stateTable[o].fail);
            }
            putchar('\n');
        }
        puts("next:");
        for (int i=0;i<size;++i) {
            printf("node %d: ",i);
            for (int j=0;j<6;++j)
                printf("%d%c",stateTable[i].next[j],j==5?'\n':' ');
        }
    }
} aho;
struct Gauss {
    double a[maxn][maxn];
    int sz;
    void build(Aho &aho) {
        memset(a,0,sizeof a);
        sz=aho.size+1;
        a[0][sz]=-1;
        for (int i=0;i<sz;++i)
            a[i][i]=-1;
        for (int i=0;i<sz;++i)
            if (!aho.stateTable[i].tag)
            for (int j=0;j<6;++j) {
                int t=aho.getnext(i,j);
                a[t][i]+=1.0/6;
            }
    }
    void swap_row(int i,int j) {
        for (int k=0;k<=sz;++k)
            swap(a[i][k],a[j][k]);
    }
    void solve() {
        for (int i=0;i<sz;++i) {
            int pivot=i;
            for (int j=i+1;j<sz;++j)
                if (fabs(a[j][i])>fabs(a[pivot][i]))
                    pivot=j;
            swap_row(i,pivot);
            if (fabs(a[i][i])<1e-12)
                return;
            for (int j=i+1;j<=sz;++j)
                a[i][j]/=a[i][i];
            for (int j=0;j<sz;++j)
                if (i!=j)
                for (int k=i+1;k<=sz;++k)
                    a[j][k]-=a[j][i]*a[i][k];
        }
    }
    void print() {
        for (int i=1;i<=n;++i)
            printf("%f%c",a[id[i]][sz],i==n?'\n':' ');
    }
    void debug() {
        for (int i=0;i<sz;++i)
            for (int j=0;j<=sz;++j)
                printf("%.3f%c",a[i][j],j==sz?'\n':' ');
    }
} gauss;
int main()
{
    scanf("%d",&T);
    while (T--) {
        scanf("%d%d",&n,&L);
        aho.init();
        for (int i=0;i<n;++i) {
            for (int j=0;j<L;++j)
                scanf("%d",&a[j]);
            aho.insert(a,i+1);
        }
        aho.build();
        gauss.build(aho);
        gauss.solve();
        gauss.print();
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值