zoukankan      html  css  js  c++  java
  • UVA 11468 Substring AC自动机+概率dp

    设dp[u][L]为当前在结点u,再走L步合法的概率。

    如果当前结点不是单词结点,并不能判定该结点一定合法,还应该沿着失配边往回走,因为可能失配边往回走的过程中出现了不合法的,不过这里不需要专门往回走,只要看last就可以知道往回走的过程中是否有单词结点了。

    都发现了这一点了,居然还是WA了。。。本来判定就慢。。。还坑多。。。万恶的uva。。。。

    先留代码,明天再调。。。

    #include<bits/stdc++.h>
    #define REP(i,a,b) for(int i=a;i<=b;i++)
    #define  MS0(a) memset(a,0,sizeof(a))
    
    using namespace std;
    
    typedef long long ll;
    const int maxn=100100;
    const int INF=1e9+10;
    
    int K,N,L;
    double pro[maxn];
    double dp[510][120];
    bool  vis[510][120];
    char s[1200][1200];
    const int cn=10+26+26;
    int idx[maxn];
    
    struct Trie
    {
        int ch[maxn][cn];
        int End[maxn];
        int f[maxn];
        int last[maxn];
        int rt,tot;
        int newnode()
        {
            ++tot;
            memset(ch[tot],-1,sizeof(ch[tot]));
            End[tot]=0;
            return tot;
        }
        void init()
        {
            tot=-1;
            rt=newnode();
        }
        void insert(char *s)
        {
            int len=strlen(s);
            int u=rt;
            REP(i,0,len-1){
                int c=idx[s[i]];
                if(ch[u][c]==-1) ch[u][c]=newnode();
                u=ch[u][c];
            }
            End[u]++;
        }
        void build()
        {
            queue<int> q;
            f[rt]=rt;last[rt]=rt;
            REP(c,0,N-1){
                if(~ch[rt][c]) f[ch[rt][c]]=rt,q.push(ch[rt][c]);
                else ch[rt][c]=rt;
            }
            while(!q.empty()){
                int u=q.front();q.pop();
                REP(c,0,N-1){
                    if(~ch[u][c]) f[ch[u][c]]=ch[f[u]][c],q.push(ch[u][c]);
                    else ch[u][c]=ch[f[u]][c];
                    if(End[f[u]]) last[u]=f[u];
                    else last[u]=last[f[u]];
                }
            }
        }
        double dfs(int u,int L)
        {
            if(vis[u][L]) return dp[u][L];
            vis[u][L]=1;
            double &res=dp[u][L];
            if(End[u]||last[u]) return res=0;
            if(L==0) return res=1;
            res=0;
            REP(c,0,N-1){
                int v=ch[u][c];
                res+=pro[c]*dfs(v,L-1);
            }
            return res;
        }
    };Trie ac;
    
    int main()
    {
        freopen("in.txt","r",stdin);
        int T;cin>>T;
        REP(casen,1,T){
            scanf("%d",&K);
            REP(i,1,K){
                scanf("%s",s[i]);
            }
            scanf("%d",&N);
            double p;char c;
            REP(i,0,N-1){
                cin>>c>>p;
                idx[c]=i;
                pro[i]=p;
            }
            ac.init();
            REP(i,1,K) ac.insert(s[i]);
            ac.build();
            scanf("%d",&L);
            MS0(vis);
            printf("Case #%d: %.6f
    ",casen,ac.dfs(ac.rt,L));
        }
        return 0;
    }
    /**
    2
    1
    a
    2
    a 0.5
    b 0.5
    2
    2
    ab
    ab
    2
    a 0.2
    b 0.8
    2
    */
    View Code

    -------------- 

    是我英语不好还是题目真坑。。。刚想关电脑睡觉,睡前把刚才第一次写的代码改了一下提交,居然过了。。。。一开始我没看到题目的“Valid characters are all alphanumeric characters”这句话,于是建立初始化字典树的时候把cn设为64(最多的情况10+26+26),但是题目明明说了“Valid characters are all alphanumeric characters”给定的字符包括所有模版串用到的字符?。。。于是我只把cn开成了N。。。

    本来就没必要改。。。按原来那样写常数大了一点,但复杂度明显不会超,牺牲一些运行效率却能大大增加代码准确性,而且可以避开题目潜在的坑。。。和数组开大点是一个道理。。

    不过重点还是前面的失配边。。。

    #include<bits/stdc++.h>
    #define REP(i,a,b) for(int i=a;i<=b;i++)
    #define  MS0(a) memset(a,0,sizeof(a))
    
    using namespace std;
    
    typedef long long ll;
    const int maxn=100100;
    const int INF=1e9+10;
    
    int K,N,L;
    double pro[maxn];
    double dp[510][120];
    bool  vis[510][120];
    char s[maxn];
    const int cn=10+26+26;
    
    int idx(char c)
    {
        if(isdigit(c)) return c-'0';
        else if(isupper(c)) return 10+c-'A';
        else return 10+26+c-'a';
    }
    
    struct Trie
    {
        int ch[maxn][cn];
        int End[maxn];
        int f[maxn];
        int last[maxn];
        int rt,tot;
        int newnode()
        {
            ++tot;
            memset(ch[tot],-1,sizeof(ch[tot]));
            End[tot]=0;
            return tot;
        }
        void init()
        {
            tot=-1;
            rt=newnode();
        }
        void insert(char *s)
        {
            int len=strlen(s);
            int u=rt;
            REP(i,0,len-1){
                int c=idx(s[i]);
                if(ch[u][c]==-1) ch[u][c]=newnode();
                u=ch[u][c];
            }
            End[u]++;
        }
        void build()
        {
            queue<int> q;
            f[rt]=rt;last[rt]=rt;
            REP(c,0,cn-1){
                if(~ch[rt][c]) f[ch[rt][c]]=rt,q.push(ch[rt][c]);
                else ch[rt][c]=rt;
            }
            while(!q.empty()){
                int u=q.front();q.pop();
                REP(c,0,cn-1){
                    if(~ch[u][c]) f[ch[u][c]]=ch[f[u]][c],q.push(ch[u][c]);
                    else ch[u][c]=ch[f[u]][c];
                    if(End[f[u]]) last[u]=f[u];
                    else last[u]=last[f[u]];
                }
            }
        }
        double dfs(int u,int L)
        {
            if(vis[u][L]) return dp[u][L];
            vis[u][L]=1;
            double &res=dp[u][L];
            if(End[u]||last[u]) return res=0;
            if(L==0) return res=1;
            res=0;
            REP(c,0,cn-1){
                int v=ch[u][c];
                res+=pro[c]*dfs(v,L-1);
            }
            return res;
        }
    };Trie ac;
    
    int main()
    {
        freopen("in.txt","r",stdin);
        int T;cin>>T;
        REP(casen,1,T){
            scanf("%d",&K);
            ac.init();
            REP(i,1,K){
                scanf("%s",s);
                ac.insert(s);
            }
            ac.build();
            scanf("%d",&N);
            REP(i,0,cn-1) pro[i]=0;
            double p;char c;
            REP(i,1,N){
                cin>>c>>p;
                pro[idx(c)]=p;
            }
            scanf("%d",&L);
            MS0(vis);
            printf("Case #%d: %.6f
    ",casen,ac.dfs(ac.rt,L));
        }
        return 0;
    }
    /**
    2
    1
    a
    2
    a 0.5
    b 0.5
    2
    2
    ab
    ab
    2
    a 0.2
    b 0.8
    2
    */
    View Code
    没有AC不了的题,只有不努力的ACMER!
  • 相关阅读:
    daper
    存储过程事务
    dengluzhucehaiyouxianshiMVC
    遍历加监听
    类的操作
    轮播图
    定时器的应用(三)
    定时器的应用(二)
    定时器的应用(一)
    延时调用
  • 原文地址:https://www.cnblogs.com/--560/p/5260312.html
Copyright © 2011-2022 走看看