zoukankan      html  css  js  c++  java
  • poj 2778(Trie图(AC自动机)+DP+矩阵乘法)

    题意:容易理解...

    思路:这个之前做的poj 1625差不多,只是1625是属于大数的,用矩阵乘法不好做(会爆栈),直接DP就行,这一题需要用到矩阵乘法来提高程序运行效率,要注意的地方就是取模运算挺慢的所以要尽量减少这种运算,开始的时候我一直RE,原来是因为m=0的时候没有考虑到。在做这题之前建议先把1625做了,这两道题最重要的还是要理解Trie图的建立方法、目的、原理。其实我还想说的就是我们写代码的时候还是要注意细节问题,在平时我们要多多积累,真正比赛的时候才不会犯一些小错误,比如这题中矩阵乘法时,我开始准备直接开二维数组来保存矩阵的,但是后来发现这样弄的话对于矩阵的计算不好算,然后学着大牛的写法,先建立一个结构体,然后结构体里面开设一个二维数组,这样的话我们进行函数调用时侯不会改变节点的值。具体看代码实现:

    这道题我参考的资料:http://hi.baidu.com/ccsu_010/item/7847a3c17f6fe2bc0d0a7b89挺好的

    poj 1625我的博客:http://www.cnblogs.com/jiangjing/archive/2013/05/02/3055431.html

    代码实现:

    #include<iostream>
    #include<string.h>
    #include<queue>
    #include<algorithm>
    using namespace std;
    struct node{
        __int64 flag;
        __int64 fail;
        __int64 next[4];
        void init()
        {
            flag=0;
            fail=0;
            memset(next,0,sizeof(next));
        }
    }s[101];
    struct yun{
        __int64 num[101][101];//用来保存矩阵
    };
    struct yun a,b;
    __int64 n,m,tot;
    void ca()//初始化
    {
        tot=0;
        s[0].init();
    }
    int hash(char temp)
    {
        if(temp=='A')
            return 0;
        else if(temp=='C')
            return 1;
        else if(temp=='G')
            return 2;
        else
            return 3;
    }
    void insert(char *str)//建立字典树
    {
        __int64 index,p=0;
        for(;*str!='\0';str++)
        {
            index=hash(*str);
            if(s[p].next[index]==0)
            {
                s[++tot].init();
                s[p].next[index]=tot;
            }
            p=s[p].next[index];
        }
        s[p].flag=1;
    }
    void AC_tree()//建立Trie图
    {
        __int64 p,cur,son,i,kao;
        queue<int>Q;
        s[0].fail=0;
        Q.push(0);
        while(!Q.empty())
        {
            p=Q.front();
            Q.pop();
            if(s[p].flag)
                continue;
            for(i=0;i<4;i++)
            {
                son=s[p].next[i];
                if(son!=0)
                {
                   if(p==0)
                     s[son].fail=0;
                   else
                   {
                       cur=s[p].fail;
                       while(cur!=0&&s[cur].next[i]==0)
                           cur=s[cur].fail;
                       s[son].fail=s[cur].next[i];
                   }
                   if(s[s[son].fail].flag==1)
                       s[son].flag=1;
                   if(s[son].flag==0&&s[p].flag==0) 
                       a.num[p][son]++;
                   Q.push(son);
                }
                else
                {
                    kao=s[s[p].fail].next[i];
                    s[p].next[i]=kao;        
                    if(s[kao].flag==0&&s[p].flag==0)
                       a.num[p][kao]++;
                }
            }
        }
    }
    struct yun xiangcheng(struct yun c,struct yun d)//矩阵相乘
    {
        __int64 i,j,k;
        struct yun e;
        for(i=0;i<=tot;i++)
            for(j=0;j<=tot;j++)
            {
                e.num[i][j]=0;
                for(k=0;k<=tot;k++)
                {
                    e.num[i][j]=e.num[i][j]+c.num[i][k]*d.num[k][j];
                    if(e.num[i][j]>=100000)
                        e.num[i][j]=e.num[i][j]%100000;
                }
            }
        return e;
    }
    void solve()//快速幂
    {
        __int64 sum=0;
        __int64 i,j;
        for(i=0;i<=tot;i++)
            for(j=0;j<=tot;j++)
                b.num[i][j]=a.num[i][j];
        m=m-1;
        while(m)
        {
            if(m%2==1)
               b=xiangcheng(b,a);
            a=xiangcheng(a,a);
            m=m/2;
        }
        for(i=0;i<=tot;i++)
        {
            sum=sum+b.num[0][i];
            if(sum>=100000)
                sum=sum%100000;
        }
        printf("%I64d\n",sum);
    }
    int main()
    {
       char str[10];
       while(scanf("%I64d%I64d",&n,&m)!=EOF)
       {
          getchar();
          ca();
          memset(a.num,0,sizeof(a.num));
          while(n--)
          {
              scanf("%s",str);
              insert(str);
          }
          if(m==0)//这里需要注意下
          {
              printf("%d\n",1);
              continue;
          }
          AC_tree();
          solve();
       }
       return 0;
    }
  • 相关阅读:
    Android OpenGL ES和OpenGL一起学(二)------理解Viewport(视口)和坐标系Android OpenGL ES篇(转帖)
    CSOM中如何取到managed metadata类型字段的类型信息
    "Value does not fall within the expected range" with managed metadata fields
    GLFW_KEY_KP_ADD和GLFW_KEY_KP_SUBTRACT
    OPENGL: WHY IS YOUR CODE PRODUCING A BLACK WINDOW?
    (转)真正的中国天气api接口xml,json(求加精) ...
    Mongo如何在多个字段中查询某个关键字?
    VS2010整合NUnit进行单元测试
    ASP.NET MVC3 学习心得------路由机制
    MVC3中 ViewBag、ViewData和TempData的使用和区别
  • 原文地址:https://www.cnblogs.com/jiangjing/p/3060799.html
Copyright © 2011-2022 走看看