• [原创]插头DP小结(ACM by kuangbin)


    这几天学习了一下插头DP,刷了11道题。对插头DP有了点理解。插头DP就先告一段落吧! 后面还有插头DP的广义路径和其它复杂应用,以后有机会再补上吧!

          kuangbin

    首先入门推荐的还是cdq的论文:《基于连通性状态压缩的动态规划问题》

    http://wenku.baidu.com/view/4fe4ac659b6648d7c1c74633.html

    上面的论文关于插头和轮廓线等概念讲得很清楚。而且关于插头DP的精髓也讲得很透了。

    插头DP其实就是每格进行状态转移。

    看懂原理和写代码还是有段距离的,可以结合代码去加深理解原理。同时形成适合自己风格的代码模板。

    HDU 1693  Eat the Trees  此题是比较基础的入门题。

    多条回路,求回路数问题。格子有障碍格子和非障碍格子两种。

    解题报告

    http://www.cnblogs.com/kuangbin/archive/2012/10/01/2709834.html

    HDU 1693
    #include<stdio.h>
    #include<string.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    const int HASH=10007;
    const int STATE=1000010;//状态数
    const int MAXD=15;
    int N,M;
    int code[MAXD],maze[MAXD][MAXD];
    
    struct HASHMAP
    {
        int head[HASH],next[STATE],state[STATE],size;
        long long f[STATE];
        void init()
        {
            size=0;
            memset(head,-1,sizeof(head));
        }
        void push(int st,long long ans)
        {
            int i,h=st%HASH;
            for(i=head[h];i!=-1;i=next[i])
              if(st==state[i])
              {
                  f[i]+=ans;
                  return;
              }
            f[size]=ans;
            state[size]=st;
            next[size]=head[h];
            head[h]=size++;
        }
    }hm[2];
    
    void decode(int *code,int m,int st)
    {
        int i;
        for(i=m;i>=0;i--)
        {
            code[i]=st&1;
            st>>=1;
        }
    }
    int encode(int *code,int m)
    {
        int i,st=0;
        for(int i=0;i<=m;i++)
        {
            st<<=1;
            st|=code[i];
        }
        return st;
    }
    void init()
    {
        int i,j;
        scanf("%d%d",&N,&M);
        for(i=1;i<=N;i++)
          for(int j=1;j<=M;j++)
            scanf("%d",&maze[i][j]);
        for(int i=1;i<=N;i++)maze[i][M+1]=0;//边界补0
        for(int i=1;i<=M;i++)maze[N+1][i]=0;
    }
    
    void shift(int *code,int m)//换行的时候移位
    {
        int i;
        for(i=m;i>0;i--)
          code[i]=code[i-1];
        code[0]=0;
    }
    
    void dpblank(int i,int j,int cur)
    {
        int k,left,up;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            left=code[j-1];
            up=code[j];
            if(left&&up)//11  -> 00
            {
                code[j-1]=code[j]=0;
                if(j==M)shift(code,M);
                hm[cur^1].push(encode(code,M),hm[cur].f[k]);
            }
            else if(left||up)//01 或 10
            {
                if(maze[i][j+1])
                {
                    code[j-1]=0;
                    code[j]=1;
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
                if(maze[i+1][j])
                {
                    code[j-1]=1;
                    code[j]=0;
                    if(j==M)shift(code,M);//这个不要忘了!
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
            }
            else
            {
                if(maze[i][j+1]&&maze[i+1][j])
                {
                    code[j]=code[j-1]=1;
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
            }
        }
    }
    
    void dpblock(int i,int j,int cur)
    {
        int k;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            code[j-1]=code[j]=0;
            if(j==M)shift(code,M);
            hm[cur^1].push(encode(code,M),hm[cur].f[k]);
        }
    }
    
    void solve()
    {
        int i,j,cur=0;
        long long ans=0;
        hm[cur].init();
        hm[cur].push(0,1);
        for(i=1;i<=N;i++)
          for(j=1;j<=M;j++)
          {
              hm[cur^1].init();
              if(maze[i][j])dpblank(i,j,cur);
              else dpblock(i,j,cur);
              cur^=1;
          }
        for(i=0;i<hm[cur].size;i++)
          ans+=hm[cur].f[i];
        printf("There are %I64d ways to eat the trees.\n",ans);
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        int T;
        int iCase=0;
        scanf("%d",&T);
        while(T--)
        {
            iCase++;
            printf("Case %d: ",iCase);
            init();
            solve();
        }
        return 0;
    }

    Ural  1519  Formula 1  和论文上的同一道题。此题是求单回路数问题,和上面的一题在状态转移时有点不同。就是形成回路一定要在最后一个非障碍格子。

    我的代码是用最小表示法做的。

    解题报告

    http://www.cnblogs.com/kuangbin/archive/2012/09/29/2708989.html

    ural 1519
    /*
    最小表示法
    */
    
    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    
    const int MAXD=15;
    const int HASH=30007;
    const int STATE=1000010;
    
    int N,M;
    int maze[MAXD][MAXD];
    int code[MAXD];
    int ch[MAXD];//最小表示法使用
    int ex,ey;//最后一个非障碍格子的坐标
    struct HASHMAP
    {
        int head[HASH],next[STATE],size;
        long long state[STATE];
        long long f[STATE];
        void init()
        {
            size=0;
            memset(head,-1,sizeof(head));
        }
        void push(long long st,long long ans)
        {
            int i;
            int h=st%HASH;
            for(i=head[h];i!=-1;i=next[i])//这里要注意是next
              if(state[i]==st)
              {
                  f[i]+=ans;
                  return;
              }
            state[size]=st;
            f[size]=ans;
            next[size]=head[h];
            head[h]=size++;
        }
    }hm[2];
    void decode(int *code,int m,long long  st)
    {
        for(int i=m;i>=0;i--)
        {
            code[i]=st&7;
            st>>=3;
        }
    }
    long long encode(int *code,int m)//最小表示法
    {
        int cnt=1;
        memset(ch,-1,sizeof(ch));
        ch[0]=0;
        long long st=0;
        for(int i=0;i<=m;i++)
        {
            if(ch[code[i]]==-1)ch[code[i]]=cnt++;
            code[i]=ch[code[i]];
            st<<=3;
            st|=code[i];
        }
        return st;
    }
    void shift(int *code,int m)
    {
        for(int i=m;i>0;i--)code[i]=code[i-1];
        code[0]=0;
    }
    void dpblank(int i,int j,int cur)
    {
        int k,left,up;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            left=code[j-1];
            up=code[j];
            if(left&&up)
            {
                if(left==up)//只能出现在最后一个非障碍格子
                {
                    if(i==ex&&j==ey)
                    {
                        code[j-1]=code[j]=0;
                        if(j==M)shift(code,M);
                        hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                    }
                }
                else//不在同一个连通分量则合并
                {
                    code[j-1]=code[j]=0;
                    for(int t=0;t<=M;t++)
                      if(code[t]==up)
                        code[t]=left;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
            }
            else if((left&&(!up))||((!left)&&up))
            {
                int t;
                if(left)t=left;
                else t=up;
                if(maze[i][j+1])
                {
                    code[j-1]=0;
                    code[j]=t;
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
                if(maze[i+1][j])
                {
                    code[j-1]=t;
                    code[j]=0;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
            }
            else//无插头,则构造新的连通块
            {
                if(maze[i][j+1]&&maze[i+1][j])
                {
                    code[j-1]=code[j]=13;
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
            }
        }
    }
    void dpblock(int i,int j,int cur)
    {
        int k;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            code[j-1]=code[j]=0;
            if(j==M)shift(code,M);
            hm[cur^1].push(encode(code,M),hm[cur].f[k]);
        }
    }
    char str[MAXD];
    void init()
    {
        memset(maze,0,sizeof(maze));
    
        ex=0;
        for(int i=1;i<=N;i++)
        {
            scanf("%s",&str);
            for(int j=0;j<M;j++)
            {
                if(str[j]=='.')
                {
                    ex=i;
                    ey=j+1;
                    maze[i][j+1]=1;
                }
            }
        }
    }
    void solve()
    {
        int i,j,cur=0;
        long long ans=0;
        hm[cur].init();
        hm[cur].push(0,1);
        for(i=1;i<=N;i++)
          for(j=1;j<=M;j++)
          {
              hm[cur^1].init();
              if(maze[i][j])dpblank(i,j,cur);
              else  dpblock(i,j,cur);
              cur^=1;
          }
        for(i=0;i<hm[cur].size;i++)
          ans+=hm[cur].f[i];
        printf("%I64d\n",ans);
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        while(scanf("%d%d",&N,&M)!=EOF)
        {
            init();
            if(ex==0)//没有空的格子
            {
                printf("0\n");
                continue;
            }
            solve();
        }
        return 0;
    }

     

    FZU 1977  Pandora adventure  此题也是单回路数问题。但是格子有了三种:障碍格子,必走格子和选择性经过格子。这样导致最后一个非障碍格子不确定。所以增加一个标志位来记录是否形成回路。

    解题报告

    http://www.cnblogs.com/kuangbin/archive/2012/10/01/2709967.html

    FZU 1977
    /*
    FZU 1977
    简单回路数问题,N*M(1<=N,M<=12)的方格中有障碍点,必走点和非必走点
    因为回路只有一条,而形成回路的最后一个点又是不确定的。
    所以额外增加一个标志位来记录是否形成回路。
    如果已经形成回路,而后面又遇到插头或者必须走的点,则该方案不合法
    G++ 375ms
    */
    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string.h>
    using namespace std;
    
    const int MAXD=15;
    const int HASH=10007;
    const int STATE=100010;
    
    int N,M;
    int code[MAXD];
    int maze[MAXD][MAXD];//0表示障碍点,1表示非必走点,2表示必走点
    int ch[MAXD];
    int isend;//是否形成回路标记位
    
    struct HASHMAP
    {
        int head[HASH],next[STATE],size;
        long long state[STATE],f[STATE];
        void init()
        {
            size=0;
            memset(head,-1,sizeof(head));
        }
        void push(long long st,long long ans)
        {
            int i,h=st%HASH;
            for(i=head[h];i!=-1;i=next[i])
                if(state[i]==st)
                {
                    f[i]+=ans;
                    return;
                }
            state[size]=st;
            f[size]=ans;
            next[size]=head[h];
            head[h]=size++;
        }
    }hm[2];
    
    void decode(int *code,int m,long long st)//注意要增加一个isend标记位
    {
        for(int i=m;i>=0;i--)
        {
            code[i]=st&7;
            st>>=3;
        }
        isend=st&1;//isend标记位在st的最高一位
    }
    long long encode(int *code,int m)//增加isend标记位
    {
        long long st=isend;//最高位
    
        int cnt=1;
        memset(ch,-1,sizeof(ch));
        ch[0]=0;
        for(int i=0;i<=m;i++)
        {
            if(ch[code[i]]==-1)ch[code[i]]=cnt++;
            code[i]=ch[code[i]];
            st<<=3;
            st|=code[i];
        }
        return st;
    }
    void shift(int *code,int m)
    {
        for(int i=m;i>0;i--)code[i]=code[i-1];
        code[0]=0;
    }
    
    void dpblank(int i,int j,int cur)
    {
        int k,left,up;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            left=code[j-1];
            up=code[j];
            if(isend)
            {//如果已经形成环路,后面又有插头或者有必过点,则是非法的
                if(left||up||maze[i][j]==2)continue;
                code[j-1]=code[j]=0;
                if(j==M)shift(code,M);
                hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                continue;
            }
            if(left&&up)
            {
                if(left==up)
                {
                    code[j-1]=code[j]=0;
                    isend=1;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
                else //不在一个连通分量则合并
                {
                    code[j-1]=code[j]=0;
                    for(int t=0;t<=M;t++)
                      if(code[t]==up)
                        code[t]=left;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
            }
            else if((left&&(!up))||((!left)&&up))
            {
                int t;
                if(left)t=left;
                else t=up;
                if(maze[i][j+1])
                {
                    code[j-1]=0;
                    code[j]=t;
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
                if(maze[i+1][j])
                {
                    code[j-1]=t;
                    code[j]=0;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
            }
            else
            {
                if(maze[i][j+1]&&maze[i+1][j])
                {
                    code[j-1]=code[j]=13;
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
                if(maze[i][j]==1)//可以经过可以不经过的点
                {
                    code[j-1]=code[j]=0;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
            }
        }
    }
    void dpblock(int i,int j,int cur)
    {
        int k;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            code[j-1]=code[j]=0;
            if(j==M)shift(code,M);
            hm[cur^1].push(encode(code,M),hm[cur].f[k]);
        }
    }
    char str[20];
    void init()
    {
        scanf("%d%d",&N,&M);
        memset(maze,0,sizeof(maze));
        for(int i=1;i<=N;i++)
        {
            scanf("%s",&str);
            for(int j=1;j<=M;j++)
            {
                if(str[j-1]=='*')maze[i][j]=1;
                else if(str[j-1]=='O')maze[i][j]=2;
            }
        }
    }
    void solve()
    {
        int i,j,cur=0;
        hm[cur].init();
        hm[cur].push(0,1);
        for(int i=1;i<=N;i++)
          for(int j=1;j<=M;j++)
          {
              hm[cur^1].init();
              if(maze[i][j])dpblank(i,j,cur);
              else dpblock(i,j,cur);
              cur^=1;
          }
        long long ans=0;
        for(i=0;i<hm[cur].size;i++)
          ans+=hm[cur].f[i];
        printf("%I64d\n",ans);
    }
    int main()
    {
       // freopen("in.txt","r",stdin);
       // freopen("out.txt","w",stdout);
        int T;
        int iCase=0;
        scanf("%d",&T);
        while(T--)
        {
            iCase++;
            printf("Case %d: ",iCase);
            init();
            solve();
        }
        return 0;
    }

     

    HDU 1964 Pipes  每个格子之间的墙壁有个花费,求用一个环经过每个格子仅一次的最小花费。此题不求方案数,只需要取最小值即可。而且所有格子都是非障碍格子,这样和Ural 1519就和类似了,而且更加简单。

    解题报告

    http://www.cnblogs.com/kuangbin/archive/2012/09/30/2709372.html

     

    HDU 1964
    /*
    HDU 1964 Pipes
    插头DP
    每个格子之间的墙壁有一个花费,求用一个环经过每个格子一次的最小花费
    G++ 46ms
    */
    
    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    const int MAXD=15;
    const int HASH=10007;
    const int STATE=1000010;
    
    struct Node
    {
        int down,right;//每个格子下边和右边墙的花费
    }node[MAXD][MAXD];
    int N,M;
    int maze[MAXD][MAXD];
    int code[MAXD];
    int ch[MAXD];//最小表示法使用
    int ex,ey;//最后一个非障碍格子的坐标
    
    struct HASHMAP
    {
        int head[HASH],next[STATE],size;
        int dp[STATE];
        long long state[STATE];//最小表示法,最大是8^11,就是2^33,所以用long long
        void init()
        {
            size=0;
            memset(head,-1,sizeof(head));
        }
        void push(long long st,int ans)
        {
            int i,h=st%HASH;
            for(i=head[h];i!=-1;i=next[i])
               if(state[i]==st)
               {
                   if(dp[i]>ans)dp[i]=ans;
                   return;
               }
            dp[size]=ans;
            state[size]=st;
            next[size]=head[h];
            head[h]=size++;
        }
    }hm[2];
    void decode(int *code,int m,long long st)
    {
        for(int i=m;i>=0;i--)
        {
            code[i]=st&7;
            st>>=3;
        }
    }
    long long encode(int *code,int m)
    {
        int cnt=1;
        memset(ch,-1,sizeof(ch));
        ch[0]=0;
        long long st=0;
        for(int i=0;i<=m;i++)
        {
            if(ch[code[i]]==-1)ch[code[i]]=cnt++;
            code[i]=ch[code[i]];
            st<<=3;
            st|=code[i];
        }
        return st;
    }
    void shift(int *code,int m)
    {
        for(int i=m;i>0;i--)code[i]=code[i-1];
        code[0]=0;
    }
    void dpblank(int i,int j,int cur)
    {
        int k,left,up;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            left=code[j-1];
            up=code[j];
            if(left&&up)
            {
                if(left==up)//只出现在最后一个格子
                {
                    if(i==ex&&j==ey)
                    {
                        code[j-1]=code[j]=0;
                        if(j==M)shift(code,M);
                        hm[cur^1].push(encode(code,M),hm[cur].dp[k]);
                    }
                }
                else
                {
                    code[j-1]=code[j]=0;
                    for(int t=0;t<=M;t++)
                        if(code[t]==left)
                             code[t]=up;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]);
                }
            }
            else if((left&&(!up))||((!left)&&up))
            {
                int t;
                if(left)t=left;
                else t=up;
                if(maze[i][j+1])
                {
                    code[j-1]=0;
                    code[j]=t;
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+node[i][j].right);
                }
                if(maze[i+1][j])
                {
                    code[j-1]=t;
                    code[j]=0;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+node[i][j].down);
                }
            }
            else//无插头
            {
                if(maze[i][j+1]&&maze[i+1][j])
                {
                    code[j-1]=code[j]=13;
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+node[i][j].down+node[i][j].right);
                }
            }
        }
    }
    char str[30];
    void init()
    {
        scanf("%d%d%*c",&N,&M);//跳过一个字符
        memset(maze,0,sizeof(maze));
        for(int i=1;i<=N;i++)
          for(int j=1;j<=M;j++)
              maze[i][j]=1;
        gets(str);
        for(int i=1;i<N;i++)
        {
            gets(str);
            for(int j=1;j<M;j++)
              node[i][j].right=str[2*j]-'0';
            gets(str);
            for(int j=1;j<=M;j++)
              node[i][j].down=str[2*j-1]-'0';
        }
        gets(str);
        for(int j=1;j<M;j++)
            node[N][j].right=str[2*j]-'0';
        gets(str);
        ex=N;
        ey=M;
    }
    void solve()
    {
        int i,j,cur=0;
        int ans=0;
        hm[cur].init();
        hm[cur].push(0,0);
        for(i=1;i<=N;i++)
          for(j=1;j<=M;j++)
          {
              hm[cur^1].init();
              dpblank(i,j,cur);
              cur^=1;
          }
        for(i=0;i<hm[cur].size;i++)
            ans+=hm[cur].dp[i];
        printf("%d\n",ans);
    }
    int main()
    {
       // freopen("in.txt","r",stdin);
       // freopen("out.txt","w",stdout);
        int T;
        scanf("%d",&T);
        while(T--)
        {
            init();
            solve();
        }
        return 0;
    }

    HDU 3377  Plan    从左上角走到右下角,每个格子有个分数。每个格子最多经过一次,可以不经过,求最大分数。 模板修改下就出来了。

    解题报告

    http://www.cnblogs.com/kuangbin/archive/2012/10/01/2709773.html

    HDU 3377
    /*
    HDU 3377
    从左上角走到右下角。每个格子有个分数。
    每个格子只能经过一次,可以不经过
    求最大分数
    G++ 140ms
    */
    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string.h>
    using namespace std;
    
    const int MAXD=15;
    const int HASH=10007;
    const int STATE=1000010;
    
    int N,M;
    int maze[MAXD][MAXD];
    int score[MAXD][MAXD];
    int code[MAXD];
    int ch[MAXD];
    
    struct HASHMAP
    {
        int head[HASH],state[STATE],next[STATE],size;
        int dp[STATE];
        void init()
        {
            size=0;
            memset(head,-1,sizeof(head));
        }
        void push(int st,int ans)
        {
            int i,h=st%HASH;
            for(i=head[h];i!=-1;i=next[i])
               if(state[i]==st)
               {
                   if(dp[i]<ans)dp[i]=ans;
                   return;
               }
            state[size]=st;
            dp[size]=ans;
            next[size]=head[h];
            head[h]=size++;
        }
    }hm[2];
    void decode(int *code,int m,int st)
    {
        for(int i=m;i>=0;i--)
        {
            code[i]=st&7;
            st>>=3;
        }
    }
    int encode(int *code,int m)
    {
        int cnt=1;
        memset(ch,-1,sizeof(ch));
        ch[0]=0;
        int st=0;
        for(int i=0;i<=m;i++)
        {
            if(ch[code[i]]==-1)ch[code[i]]=cnt++;
            code[i]=ch[code[i]];
            st<<=3;
            st|=code[i];
        }
        return st;
    }
    void shift(int *code,int m)
    {
        for(int i=m;i>0;i--)code[i]=code[i-1];
        code[0]=0;
    }
    
    void dpblank(int i,int j,int cur)
    {
        int k,left,up;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            left=code[j-1];
            up=code[j];
            if((i==1&&j==1)||(i==N&&j==M))
            {
                if((left&&(!up))||((!left)&&up))
                {
                    code[j-1]=code[j]=0;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+score[i][j]);
                }
                else if(left==0&&up==0)
                {
                    if(maze[i][j+1])
                    {
                        code[j-1]=0;
                        code[j]=13;
                        hm[cur^1].push(encode(code,M),hm[cur].dp[k]+score[i][j]);
                    }
                    if(maze[i][j+1])
                    {
                        code[j-1]=13;
                        code[j]=0;
                        if(j==M)shift(code,M);
                        hm[cur^1].push(encode(code,M),hm[cur].dp[k]+score[i][j]);
                    }
                }
                continue;
            }
            if(left&&up)
            {
                if(left==up)//没有这种情况,因为不形成环
                {
    
                }
                else
                {
                    code[j-1]=code[j]=0;
                    for(int t=0;t<=M;t++)//这里少了个等号,查了好久的错
                      if(code[t]==up)
                        code[t]=left;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+score[i][j]);
                }
            }
            else if((left&&(!up))||((!left)&&up))
            {
                int t;
                if(left)t=left;
                else t=up;
                if(maze[i][j+1])
                {
                    code[j-1]=0;
                    code[j]=t;
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+score[i][j]);
                }
                if(maze[i+1][j])
                {
                    code[j]=0;
                    code[j-1]=t;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+score[i][j]);
                }
            }
            else
            {
                if(maze[i][j+1]&&maze[i+1][j])
                {
                    code[j]=code[j-1]=13;
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+score[i][j]);
                }
                code[j-1]=code[j]=0;
                if(j==M)shift(code,M);
                hm[cur^1].push(encode(code,M),hm[cur].dp[k]);
            }
        }
    }
    
    void init()
    {
        memset(maze,0,sizeof(maze));
        for(int i=1;i<=N;i++)
          for(int j=1;j<=M;j++)
          {
              maze[i][j]=1;
              scanf("%d",&score[i][j]);
          }
    }
    void solve()
    {
        int i,j,cur=0;
        hm[cur].init();
        hm[cur].push(0,0);
        for(int i=1;i<=N;i++)
          for(int j=1;j<=M;j++)
          {
              hm[cur^1].init();
              dpblank(i,j,cur);
              cur^=1;
          }
        int ans=0;
        for(int i=0;i<hm[cur].size;i++)
           ans+=hm[cur].dp[i];
        printf("%d\n",ans);
    }
    int main()
    {
       // freopen("in.txt","r",stdin);
       // freopen("out.txt","w",stdout);
        int iCase=0;
        while(scanf("%d%d",&N,&M)!=EOF)
        {
            iCase++;
            printf("Case %d: ",iCase);
            init();
            if(N==1&&M==1)
            {
                printf("%d\n",score[1][1]);
                continue;
            }
            solve();
        }
        return 0;
    }
    
    /*
    Sample Input
    2 2
    1 2
    3 1
    3 3
    0 -20 100
    1 -20 -20
    1   1   1
    
    
    Sample Output
    Case 1: 5
    Case 2: 61
    
    */

     

    POJ  1739  Tony's Tour   楼教主的男人八题之一。从左下角走到右下角,每个非障碍格子仅走一次的方法数。一种方法是在后面增加两行转换成回路问题,这样就和ural 1519一样了。也可以不增加行,直接特殊处理下即可。

    解题报告

    http://www.cnblogs.com/kuangbin/archive/2012/09/30/2709114.html

    POJ 1739
    /*
    POJ 1739
    题目意思就是从左下角走到右下角,每个非障碍格子都走一遍的方法数
    转换成回路问题。
    在最后加两行
       .########.
       ..........
    这样就转成回路问题了,就和URAL 1519 一样的做法了
    
    G++ 47ms
    */
    #include<iostream>
    #include<string.h>
    #include<algorithm>
    #include<stdio.h>
    using namespace std;
    
    const int MAXD=15;
    const int HASH=10007;
    const int STATE=1000010;
    
    int N,M;
    int maze[MAXD][MAXD];
    int code[MAXD];
    int ch[MAXD];//最小表示法使用
    int ex,ey;//最后一个非障碍格子的坐标
    
    struct HASHMAP
    {
        int head[HASH],next[STATE],size;
        long long state[STATE],f[STATE];
        void init()
        {
            size=0;
            memset(head,-1,sizeof(head));
        }
        void push(long long st,long long ans)
        {
            int i;
            int h=st%HASH;
            for(i=head[h];i!=-1;i=next[i])
              if(state[i]==st)
              {
                  f[i]+=ans;
                  return;
              }
            state[size]=st;
            f[size]=ans;
            next[size]=head[h];
            head[h]=size++;
        }
    }hm[2];
    
    void decode(int *code,int m,long long st)
    {
        for(int i=m;i>=0;i--)
        {
            code[i]=st&7;
            st>>=3;
        }
    }
    long long encode(int *code,int m)
    {
        int cnt=1;
        memset(ch,-1,sizeof(ch));
        ch[0]=0;
        long long st=0;
        for(int i=0;i<=m;i++)
        {
            if(ch[code[i]]==-1)ch[code[i]]=cnt++;
            code[i]=ch[code[i]];
            st<<=3;
            st|=code[i];
        }
        return st;
    }
    void shift(int *code,int m)
    {
        for(int i=m;i>0;i--)code[i]=code[i-1];
        code[0]=0;
    }
    
    void dpblank(int i,int j,int cur)
    {
        int k,left,up;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            left=code[j-1];
            up=code[j];
            if(left&&up)
            {
                if(left==up)
                {
                    if(i==ex&&j==ey)//只能出现在最后一个非障碍格子
                    {
                        code[j]=code[j-1]=0;
                        if(j==M)shift(code,M);
                        hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                    }
                }
                else //不在同一个连通分量则合并
                {
                    code[j-1]=code[j]=0;
                    for(int t=0;t<=M;t++)
                      if(code[t]==left)
                        code[t]=up;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
            }
            else if((left&&(!up))||((!left)&&up))
            {
                int t;
                if(left)t=left;
                else t=up;
                if(maze[i][j+1])
                {
                    code[j-1]=0;
                    code[j]=t;
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
                if(maze[i+1][j])
                {
                    code[j-1]=t;
                    code[j]=0;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
            }
            else
            {
                if(maze[i][j+1]&&maze[i+1][j])
                {
                    code[j-1]=code[j]=13;
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
            }
        }
    }
    void dpblock(int i,int j,int cur)
    {
        int k;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            code[j-1]=code[j]=0;
            if(j==M)shift(code,M);
            hm[cur^1].push(encode(code,M),hm[cur].f[k]);
        }
    }
    char str[20];
    void init()
    {
        memset(maze,0,sizeof(maze));
        for(int i=1;i<=N;i++)
        {
            scanf("%s",&str);
            for(int j=0;j<M;j++)
              if(str[j]=='.')
              {
                  maze[i][j+1]=1;
              }
        }
        maze[N+1][1]=maze[N+1][M]=1;
        for(int i=2;i<M;i++)maze[N+1][i]=0;
        for(int i=1;i<=M;i++)maze[N+2][i]=1;
        N+=2;
        ex=N,ey=M;
    }
    void solve()
    {
        int i,j,cur=0;
        hm[cur].init();
        hm[cur].push(0,1);
        for(i=1;i<=N;i++)
          for(j=1;j<=M;j++)
          {
              hm[cur^1].init();
              if(maze[i][j])dpblank(i,j,cur);
              else dpblock(i,j,cur);
              cur^=1;
          }
        long long ans=0;
        for(int i=0;i<hm[cur].size;i++)
          ans+=hm[cur].f[i];
        printf("%I64d\n",ans);
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        while(scanf("%d%d",&N,&M))
        {
            if(N==0&&M==0)break;
            init();
            solve();
        }
        return 0;
    }
    POJ 1739
    /*
    POJ 1739
    不增加行。
    起点和终点特殊处理
    
    G++ 47ms
    */
    #include<iostream>
    #include<string.h>
    #include<algorithm>
    #include<stdio.h>
    using namespace std;
    
    const int MAXD=15;
    const int HASH=10007;
    const int STATE=1000010;
    
    int N,M;
    int maze[MAXD][MAXD];
    int code[MAXD];
    int ch[MAXD];//最小表示法使用
    int ex,ey;//最后一个非障碍格子的坐标
    
    struct HASHMAP
    {
        int head[HASH],next[STATE],size;
        long long state[STATE],f[STATE];
        void init()
        {
            size=0;
            memset(head,-1,sizeof(head));
        }
        void push(long long st,long long ans)
        {
            int i;
            int h=st%HASH;
            for(i=head[h];i!=-1;i=next[i])
              if(state[i]==st)
              {
                  f[i]+=ans;
                  return;
              }
            state[size]=st;
            f[size]=ans;
            next[size]=head[h];
            head[h]=size++;
        }
    }hm[2];
    
    void decode(int *code,int m,long long st)
    {
        for(int i=m;i>=0;i--)
        {
            code[i]=st&7;
            st>>=3;
        }
    }
    long long encode(int *code,int m)
    {
        int cnt=1;
        memset(ch,-1,sizeof(ch));
        ch[0]=0;
        long long st=0;
        for(int i=0;i<=m;i++)
        {
            if(ch[code[i]]==-1)ch[code[i]]=cnt++;
            code[i]=ch[code[i]];
            st<<=3;
            st|=code[i];
        }
        return st;
    }
    void shift(int *code,int m)
    {
        for(int i=m;i>0;i--)code[i]=code[i-1];
        code[0]=0;
    }
    
    void dpblank(int i,int j,int cur)
    {
        int k,left,up;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            left=code[j-1];
            up=code[j];
    
            if((i==N&&j==1)||(i==N&&j==M))//起点和终点
            {
                if((left&&(!up))||((!left)&&up))
                {
                    code[j]=code[j-1]=0;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
                else if(left==0&&up==0)
                {
                    if(maze[i][j+1])
                    {
                       code[j-1]=0;
                       code[j]=13;
                       hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                    }
                    if(maze[i+1][j])
                    {
                       code[j-1]=13;
                       code[j]=0;
                       if(j==M)shift(code,M);
                       hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                    }
                }
                continue;
            }
            if(left&&up)
            {
                if(left==up)
                {//这种情况不能发生
                   /* if(i==ex&&j==ey)//只能出现在最后一个非障碍格子
                    {
                        code[j]=code[j-1]=0;
                        if(j==M)shift(code,M);
                        hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                    }*/
                }
                else //不在同一个连通分量则合并
                {
                    code[j-1]=code[j]=0;
                    for(int t=0;t<=M;t++)
                      if(code[t]==left)
                        code[t]=up;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
            }
            else if((left&&(!up))||((!left)&&up))
            {
                int t;
                if(left)t=left;
                else t=up;
                if(maze[i][j+1])
                {
                    code[j-1]=0;
                    code[j]=t;
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
                if(maze[i+1][j])
                {
                    code[j-1]=t;
                    code[j]=0;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
            }
            else
            {
                if(maze[i][j+1]&&maze[i+1][j])
                {
                    code[j-1]=code[j]=13;
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
            }
        }
    }
    void dpblock(int i,int j,int cur)
    {
        int k;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            code[j-1]=code[j]=0;
            if(j==M)shift(code,M);
            hm[cur^1].push(encode(code,M),hm[cur].f[k]);
        }
    }
    char str[20];
    void init()
    {
        memset(maze,0,sizeof(maze));
        for(int i=1;i<=N;i++)
        {
            scanf("%s",&str);
            for(int j=0;j<M;j++)
              if(str[j]=='.')
              {
                  maze[i][j+1]=1;
              }
        }
    }
    void solve()
    {
        int i,j,cur=0;
        hm[cur].init();
        hm[cur].push(0,1);
        for(i=1;i<=N;i++)
          for(j=1;j<=M;j++)
          {
              hm[cur^1].init();
              if(maze[i][j])dpblank(i,j,cur);
              else dpblock(i,j,cur);
              cur^=1;
          }
        long long ans=0;
        for(int i=0;i<hm[cur].size;i++)
          ans+=hm[cur].f[i];
        printf("%I64d\n",ans);
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
       // freopen("out.txt","w",stdout);
        while(scanf("%d%d",&N,&M))
        {
            if(N==0&&M==0)break;
            init();
            solve();
        }
        return 0;
    }

     

    POJ  3133  Manhattan Wiring   格子中有两个2,两个3.求把两个2连起来,两个3连起来。求经过总的格子数的总和减2.  两条路径不能交叉。有障碍格子。非障碍格子最多经过一次。插头出需要记录三种状态:没有插头、2号插头、3号插头。可以用三进制。但是考虑到4进制更加高效,我用的四进制做的。

    解题报告

    http://www.cnblogs.com/kuangbin/archive/2012/09/30/2709263.html

     

    POJ 3133
    /*
    POJ 3133
    连接2的插头为2,连接3的插头为3
    没有插头为0
    用四进制表示(四进制比三进制高效)
    
    G++ 391ms
    */
    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    const int MAXD=15;
    const int HASH=10007;
    const int STATE=1000010;
    int N,M;
    int maze[MAXD][MAXD];//0表示障碍,1是非障碍,2和3
    int code[MAXD];
    //0表示没有插头,2表示和插头2相连,3表示和插头3相连
    
    struct HASHMAP
    {
        int head[HASH],next[STATE],size;
        int state[STATE];
        int dp[STATE];
        void init()
        {
            size=0;
            memset(head,-1,sizeof(head));
        }
        void push(int st,int ans)
        {
            int i,h=st%HASH;
            for(i=head[h];i!=-1;i=next[i])
              if(state[i]==st)
              {
                  if(dp[i]>ans)dp[i]=ans;
                  return;
              }
            state[size]=st;
            dp[size]=ans;
            next[size]=head[h];
            head[h]=size++;
        }
    }hm[2];
    void decode(int *code,int m,int st)//四进制
    {
        int i;
        for(int i=m;i>=0;i--)
        {
            code[i]=(st&3);
            st>>=2;
        }
    }
    int encode(int *code,int m)
    {
        int i;
        int st=0;
        for(int i=0;i<=m;i++)
        {
            st<<=2;
            st|=code[i];
        }
        return st;
    }
    void shift(int *code,int m)//换行
    {
        for(int i=m;i>0;i--)code[i]=code[i-1];
        code[0]=0;
    }
    void dpblank(int i,int j,int cur)
    {
        int k,left,up;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            left=code[j-1];
            up=code[j];
            if(left&&up)
            {
                if(left==up)//只能是相同的插头
                {
                    code[j-1]=code[j]=0;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);
                }
            }
            else if((left&&(!up))||((!left)&&up))//只有一个插头
            {
                int t;
                if(left)t=left;
                else t=up;//这里少写个else ,查了好久的错误
                if(maze[i][j+1]==1||maze[i][j+1]==t)//插头从右边出来
                {
                    code[j-1]=0;
                    code[j]=t;
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);
                }
                if(maze[i+1][j]==1||maze[i+1][j]==t)//插头从下边出来
                {
                    code[j]=0;
                    code[j-1]=t;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);
                }
            }
            else if(left==0&&up==0)//没有插头
            {
                code[j-1]=code[j]=0;//不加插头
                if(j==M)shift(code,M);
                hm[cur^1].push(encode(code,M),hm[cur].dp[k]);
                if(maze[i][j+1]&&maze[i+1][j])
                {
                    if(maze[i][j+1]==1&&maze[i+1][j]==1)
                    {
                        decode(code,M,hm[cur].state[k]);
                        code[j-1]=code[j]=2;//加2号插头
                        hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);
                        //decode(code,M,hm[cur].state[k]);
                        code[j-1]=code[j]=3;//加3号插头
                        hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);
                    }
                    else if((maze[i][j+1]==2&&maze[i+1][j]==1)||(maze[i+1][j]==2&&maze[i][j+1]==1)||(maze[i][j+1]==2&&maze[i+1][j]==2))
                    {
                        decode(code,M,hm[cur].state[k]);
                        code[j-1]=code[j]=2;
                        hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);
                    }
                    else if((maze[i][j+1]==3&&maze[i+1][j]==1)||(maze[i+1][j]==3&&maze[i][j+1]==1)||(maze[i][j+1]==3&&maze[i+1][j]==3))
                    {
                        decode(code,M,hm[cur].state[k]);
                        code[j-1]=code[j]=3;
                        hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);
                    }
                }
            }
        }
    }
    void dpblock(int i,int j,int cur)
    {
        int k;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            if(code[j-1]!=0||code[j]!=0)continue;
            code[j-1]=code[j]=0;//不加插头
            if(j==M)shift(code,M);
            hm[cur^1].push(encode(code,M),hm[cur].dp[k]);
        }
    }
    void dp_2(int i,int j,int cur)
    {
        int left,up,k;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            left=code[j-1];
            up=code[j];
            if((left==2&&up==0)||(left==0&&up==2))
            {
                code[j-1]=code[j]=0;
                if(j==M)shift(code,M);
                hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);
            }
            else if(left==0&&up==0)
            {
                if(maze[i][j+1]==1||maze[i][j+1]==2)
                {
                    code[j-1]=0;
                    code[j]=2;
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);
                }
                if(maze[i+1][j]==1||maze[i+1][j]==2)
                {
                    code[j-1]=2;
                    code[j]=0;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);
                }
            }
        }
    }
    void dp_3(int i,int j,int cur)
    {
        int left,up,k;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            left=code[j-1];
            up=code[j];
            if((left==3&&up==0)||(left==0&&up==3))
            {
                code[j-1]=code[j]=0;
                if(j==M)shift(code,M);
                hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);
            }
            else if(left==0&&up==0)
            {
                if(maze[i][j+1]==1||maze[i][j+1]==3)
                {
                    code[j-1]=0;
                    code[j]=3;
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);
                }
                if(maze[i+1][j]==1||maze[i+1][j]==3)
                {
                    code[j-1]=3;
                    code[j]=0;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);
                }
            }
        }
    }
    
    void init()
    {
        memset(maze,0,sizeof(maze));
        for(int i=1;i<=N;i++)
          for(int j=1;j<=M;j++)
          {
              scanf("%d",&maze[i][j]);
              //if(maze[i][j]==0)maze[i][j]=1;
              //if(maze[i][j]==1)maze[i][j]=0;
              //上面的写法是错的,!!!
              if(maze[i][j]==1||maze[i][j]==0)maze[i][j]^=1;//0变1,1变0
          }
    }
    void solve()
    {
        int i,j,cur=0;
        hm[cur].init();
        hm[cur].push(0,0);
        for(int i=1;i<=N;i++)
          for(int j=1;j<=M;j++)
          {
              hm[cur^1].init();
              if(maze[i][j]==0)dpblock(i,j,cur);
              else if(maze[i][j]==1)dpblank(i,j,cur);
              else if(maze[i][j]==2)dp_2(i,j,cur);
              else if(maze[i][j]==3)dp_3(i,j,cur);
              cur^=1;
          }
        int ans=0;
        for(int i=0;i<hm[cur].size;i++)
          ans+=hm[cur].dp[i];
        if(ans>0)ans-=2;
        printf("%d\n",ans);
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        while(scanf("%d%d",&N,&M))
        {
            if(N==0&&M==0)break;
            init();
            solve();
        }
        return 0;
    }

    ZOJ  3466 The Hive II  和HDU 1693一样,求多回路问题。但是四边形换成了六边行。难度相应提高了。做的方法是一样的。我是倒过来,按照列来转移的,稍微简单一下。按照行可以做,但是讨论比较多,我没有去尝试。

    解题报告

    http://www.cnblogs.com/kuangbin/archive/2012/09/29/2708909.html

    ZOJ 3466
    /*
    ZOJ 3466
    C++ 3850ms 62768K
    原来ZOJ中的long long要用%lld输出啊
    对ZOJ不熟悉啊,被坑了好久
    
    */
    
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    
    const int HASH=10007;
    const int STATE=2000010;
    const int MAXD=32;
    int N,M;
    int code[MAXD],maze[MAXD][MAXD];
    
    struct HASHMAP
    {
        int head[HASH],next[STATE],state[STATE],size;
        long long f[STATE];
        void init()
        {
            size=0;
            memset(head,-1,sizeof(head));
        }
        void push(int st,long long ans)
        {
            int i,h=st%HASH;
            for(i=head[h];i!=-1;i=next[i])
              if(st==state[i])
              {
                  f[i]+=ans;
                  return;
              }
            f[size]=ans;
            state[size]=st;
            next[size]=head[h];
            head[h]=size++;
        }
    }hm[2];
    void decode(int *code,int m,int st)
    {
        int i;
        for(i=m;i>=0;i--)
        {
            code[i]=st&1;
            st>>=1;
        }
    }
    int encode(int *code,int m)
    {
        int i,st=0;
        for(i=0;i<=m;i++)
        {
            st<<=1;
            st|=code[i];
        }
        return st;
    }
    void init()
    {
        N=8;//倒过来,8行
        int t;
        scanf("%d",&t);
        memset(maze,0,sizeof(maze));
        for(int i=1;i<=N;i++)
          for(int j=1;j<=M;j++)
            maze[i][j]=1;
        char str[10];
        while(t--)
        {
            scanf("%s",&str);
            maze[str[1]-'A'+1][M-(str[0]-'A')]=0;
        }
    }
    void shift(int *code,int m)//偶数行换奇数行的时候要变化
    {
        for(int i=m;i>1;i--)
          code[i]=code[i-2];
        code[0]=0;
        code[1]=0;
    }
    void dpblank(int i,int j,int cur)
    {
        int k,left,up1,up2;
        int t1,t2;
        if(i%2==0)t1=j,t2=j+1;
        else t1=j-1,t2=j;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,2*M,hm[cur].state[k]);
            left=code[2*(j-1)];
            up1=code[2*j-1];
            up2=code[2*j];
           // printf("%d %d:  %d  %d  %d\n",i,j,left,up1,up2);
            if((left==1&&up1==1&&up2==0)||(left==0&&up1==1&&up2==1)||(left==1&&up1==0&&up2==1))
            {
                code[2*j-2]=code[2*j-1]=code[2*j]=0;
                if(j==M&&i%2==0)shift(code,2*M);
                hm[cur^1].push(encode(code,2*M),hm[cur].f[k]);
            }
            else if((left==1&&up1==0&&up2==0)||(left==0&&up1==1&&up2==0)||(left==0&&up1==0&&up2==1))
            {
                if(maze[i+1][t1])
                {
                    code[2*j-2]=1;
                    code[2*j-1]=code[2*j]=0;
                    if(j==M&&i%2==0)shift(code,2*M);
                    hm[cur^1].push(encode(code,2*M),hm[cur].f[k]);
                }
                if(maze[i+1][t2])
                {
                    code[2*j-2]=code[2*j]=0;
                    code[2*j-1]=1;
                    hm[cur^1].push(encode(code,2*M),hm[cur].f[k]);
                }
                if(maze[i][j+1])
                {
                    code[2*j-2]=code[2*j-1]=0;
                    code[2*j]=1;
                    hm[cur^1].push(encode(code,2*M),hm[cur].f[k]);
                }
            }
            else if(left==0&&up1==0&&up2==0)
            {
                if(maze[i+1][t1]&&maze[i+1][t2])
                {
                    code[2*j-2]=code[2*j-1]=1;
                    code[2*j]=0;
                    hm[cur^1].push(encode(code,2*M),hm[cur].f[k]);
                }
                if(maze[i+1][t1]&&maze[i][j+1])
                {
                    code[2*j-2]=code[2*j]=1;
                    code[2*j-1]=0;
                    hm[cur^1].push(encode(code,2*M),hm[cur].f[k]);
                }
                if(maze[i+1][t2]&&maze[i][j+1])
                {
                    code[2*j-2]=0;
                    code[2*j-1]=code[2*j]=1;
                    hm[cur^1].push(encode(code,2*M),hm[cur].f[k]);
                }
            }
        }
    }
    void dpblock(int i,int j,int cur)
    {
        int k;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,2*M,hm[cur].state[k]);
            code[2*j-2]=code[2*j-1]=code[2*j]=0;
            if(j==M&&i%2==0)shift(code,2*M);
            hm[cur^1].push(encode(code,2*M),hm[cur].f[k]);
        }
    }
    void solve()
    {
        int i,j,cur=0;
        long long ans=0;
        hm[cur].init();
        hm[cur].push(0,1);
        for(i=1;i<=N;i++)
          for(j=1;j<=M;j++)
          {
              hm[cur^1].init();
              if(maze[i][j])dpblank(i,j,cur);
              else dpblock(i,j,cur);
              cur^=1;
          }
        for(i=0;i<hm[cur].size;i++)
          if(hm[cur].state[i]==0)
             ans+=hm[cur].f[i];
        printf("%lld\n",ans);//ZOJ中的C++要lld才能AC的
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        while(scanf("%d",&M)!=EOF)
        {
            init();
            solve();
        }
        return 0;
    }

     

     

    ZOJ  3256  Tour in the Castle   这题数据很大。求左上角到右下角的路径数。经过所以格子一次。要用矩阵加速。由于每一列都是一样的,状态转移就相同。用插头DP求出列与列之间的状态转移,然后用矩阵乘法。这题比较难

    解题报告

    http://www.cnblogs.com/kuangbin/archive/2012/10/01/2709831.html

    ZOJ 3256
    /*
    ZOJ 3256
    N*M(2<=N<=7,1<=M<=10^9)的方格,问从左上角的格子到左下角的格子,
    而且仅经过所有格子一次的路径数
    插头DP+矩阵加速
    
    对于一个图的邻接矩阵的N次方,其中(i,j)位置上的元素表示
    点i经过N步到达点j的方案数
    */
    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string.h>
    using namespace std;
    
    const int STATE=1010;
    const int HASH=419;//这个小一点,效率高
    const int MOD=7777777;
    
    int N,M;
    int D;
    int code[10];
    int ch[10];
    int g[200][200];//状态转移图
    
    struct Matrix
    {
        int n,m;
        int mat[200][200];
    };
    Matrix mul(Matrix a,Matrix b)//矩阵相乘,要保证a的列数和b的行数相等
    {
        Matrix ret;
        ret.n=a.n;
        ret.m=b.m;
        long long sum;
        for(int i=0;i<a.n;i++)
           for(int j=0;j<b.m;j++)
           {
               sum=0;
               for(int k=0;k<a.m;k++)
               {
                   sum+=(long long)a.mat[i][k]*b.mat[k][j];
                   //sum%=MOD;//加了这句话就会TLE,坑啊。。。
               }
               ret.mat[i][j]=sum%MOD;
           }
        return ret;
    }
    Matrix pow_M(Matrix a,int n)//方阵的n次方
    {
        Matrix ret=a;
        memset(ret.mat,0,sizeof(ret.mat));
        for(int i=0;i<a.n;i++)ret.mat[i][i]=1;//单位阵
        Matrix temp=a;
        while(n)
        {
            if(n&1)ret=mul(ret,temp);
            temp=mul(temp,temp);
            n>>=1;
        }
        return ret;
    }
    
    struct HASHMAP
    {
        int head[HASH],next[STATE],size;
        int state[STATE];
        void init()
        {
            size=0;
            memset(head,-1,sizeof(head));
        }
        int push(int st)
        {
            int i,h=st%HASH;
            for(i=head[h];i!=-1;i=next[i])
               if(state[i]==st)
                  return i;
            state[size]=st;
            next[size]=head[h];
            head[h]=size++;
            return size-1;
        }
    }hm;
    void decode(int *code,int n,int st)
    {
        for(int i=n-1;i>=0;i--)
        {
            code[i]=st&3;
            st>>=2;
        }
    }
    int encode(int *code,int n)
    {
        int cnt=1;
        memset(ch,-1,sizeof(ch));
        ch[0]=0;
        int st=0;
        for(int i=0;i<n;i++)
        {
            if(ch[code[i]]==-1)ch[code[i]]=cnt++;
            code[i]=ch[code[i]];
            st<<=2;
            st|=code[i];
        }
        return st;
    }
    
    bool check(int st,int nst)//判断两种状态能不能转移
    {
        decode(code,N,st);
        int flag=0;//标记格子上边是否有插头
        int cnt=0;
        int k;
        for(int i=0;i<N;i++)
        {
            if(flag==0)//这个格子上边没有插头
            {
                if(code[i]==0&&(nst&(1<<i))==0)//左边和右边都没有插头
                   return false;
                if(code[i]&&(nst&(1<<i)))continue;
                if(code[i])flag=code[i];//插头从左边过来,从下边出去
                else flag=-1;//插头从下边进来从右边出去
                k=i;
            }
            else
            {
                if(code[i]&&(nst&(1<<i)))//左边和右边和上边都有插头
                   return false;
                if(code[i]==0&&(nst&(1<<i))==0)continue;
                if(code[i])
                {
                    if(code[i]==flag&&((nst!=0)||i!=N-1))return false;//只有最后一个格子才能合起来
                    if(flag>0)
                    {
                        for(int j=0;j<N;j++)
                          if(code[j]==code[i]&&j!=i)
                              code[j]=code[k];
                        code[i]=code[k]=0;
                    }
                    else
                    {
                        code[k]=code[i];
                        code[i]=0;
                    }
                }
                else
                {
                    if(flag>0)code[i]=code[k],code[k]=0;
                    else code[i]=code[k]=N+(cnt++);
                }
                flag=0;
            }
        }
        if(flag!=0)return false;
        return true;
    }
    struct Node
    {
        int g[200][200];
        int D;
    }node[20];//打表之用
    void init()
    {
        if(node[N].D!=0)
        {
            memcpy(g,node[N].g,sizeof(node[N].g));
            D=node[N].D;
            return;
        }
        int st,nst;
        hm.init();
        memset(code,0,sizeof(code));
        code[0]=code[N-1]=1;
        hm.push(0);
        hm.push(encode(code,N));
        memset(g,0,sizeof(g));
        for(int i=1;i<hm.size;i++)
        {
            st=hm.state[i];
            for(nst=0;nst<(1<<N);nst++)
              if(check(st,nst))
              {
                  int j=hm.push(encode(code,N));
                  g[i][j]=1;
              }
        }
        D=hm.size;
        memcpy(node[N].g,g,sizeof(g));
        node[N].D=D;
    }
    void solve()
    {
        Matrix temp;
        temp.n=temp.m=D;
        memcpy(temp.mat,g,sizeof(g));
        Matrix ans=pow_M(temp,M);
        if(ans.mat[1][0]==0)printf("Impossible\n");
        else printf("%d\n",ans.mat[1][0]%MOD);
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        for(int i=0;i<20;i++)node[i].D=0;
        while(scanf("%d%d",&N,&M)==2)
        {
            init();
            solve();
        }
        return 0;
    }

     

    ZOJ  3213  Beautiful Meadow   此题求简单路径。得到最大的分数。

    用最小表示法,需要增加标志位记录独立插头个数。要使独立插头个数小于等于2.

    解题报告

    http://www.cnblogs.com/kuangbin/archive/2012/10/02/2710055.html

    ZOJ 3213
    /*
    ZOJ 3213
    */
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    
    const int MAXD=15;
    const int HASH=10007;
    const int STATE=1000010;
    
    int N,M;
    int maze[MAXD][MAXD];
    int code[MAXD];
    int ch[MAXD];
    int num;//独立插头的个数
    int ans;//答案
    
    struct HASHMAP
    {
        int head[HASH],next[STATE],size;
        int state[STATE],dp[STATE];
        void init()
        {
            size=0;
            memset(head,-1,sizeof(head));
        }
        void push(int st,int ans)
        {
            int i,h=st%HASH;
            for(i=head[h];i!=-1;i=next[i])
              if(state[i]==st)
              {
                  if(dp[i]<ans)dp[i]=ans;
                  return;
              }
            state[size]=st;
            dp[size]=ans;
            next[size]=head[h];
            head[h]=size++;
        }
    }hm[2];
    void decode(int *code,int m,int st)
    {
        num=st&7;//独立插头个数
        st>>=3;
        for(int i=m;i>=0;i--)
        {
            code[i]=st&7;
            st>>=3;
        }
    }
    int encode(int *code,int m)
    {
        int cnt=1;
        memset(ch,-1,sizeof(ch));
        ch[0]=0;
        int st=0;
        for(int i=0;i<=m;i++)
        {
            if(ch[code[i]]==-1)ch[code[i]]=cnt++;
            code[i]=ch[code[i]];
            st<<=3;
            st|=code[i];
        }
        st<<=3;
        st|=num;
        return st;
    }
    void shift(int *code,int m)
    {
        for(int i=m;i>0;i--)code[i]=code[i-1];
        code[0]=0;
    }
    void dpblank(int i,int j,int cur)
    {
        int k,left,up;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            left=code[j-1];
            up=code[j];
            if(left&&up)
            {
                if(left!=up)
                {
                    code[j-1]=code[j]=0;
                    for(int t=0;t<=M;t++)
                      if(code[t]==up)
                         code[t]=left;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+maze[i][j]);
                   // hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].dp[k]+maze[i][j]);
                }
            }
            else if(left||up)
            {
                int t;
                if(left)t=left;
                else t=up;
                if(maze[i][j+1])
                {
                    code[j-1]=0;
                    code[j]=t;
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+maze[i][j]);
                }
                if(maze[i+1][j])
                {
                    code[j-1]=t;
                    code[j]=0;
                   hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].dp[k]+maze[i][j]);
                }
                if(num<2)
                {
                    num++;
                    code[j-1]=code[j]=0;
                    hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].dp[k]+maze[i][j]);
                }
            }
            else
            {
                code[j-1]=code[j]=0;
               hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].dp[k]);
                if(maze[i][j+1]&&maze[i+1][j])
                {
                    code[j-1]=code[j]=13;
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+maze[i][j]);
                }
                if(num<2)
                {
                    num++;
                    if(maze[i][j+1])
                    {
                        code[j]=13;
                        code[j-1]=0;
                        hm[cur^1].push(encode(code,M),hm[cur].dp[k]+maze[i][j]);
                    }
                    if(maze[i+1][j])
                    {
                        code[j-1]=13;
                        code[j]=0;
                       hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].dp[k]+maze[i][j]);
                    }
                }
            }
        }
    }
    void dpblock(int i,int j,int cur)
    {
        int k;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);//这个忘记了!!!
            code[j-1]=code[j]=0;
            if(j==M)shift(code,M);
            hm[cur^1].push(encode(code,M),hm[cur].dp[k]);
        }
    }
    void init()
    {
        scanf("%d%d",&N,&M);
        ans=0;
        memset(maze,0,sizeof(maze));//初始化别忘记了
        for(int i=1;i<=N;i++)
          for(int j=1;j<=M;j++)
          {
              scanf("%d",&maze[i][j]);
              if(maze[i][j]>ans)ans=maze[i][j];
          }
    }
    void solve()
    {
        int i,j,cur=0;
        hm[cur].init();
        hm[cur].push(0,0);
        for(i=1;i<=N;i++)
           for(int j=1;j<=M;j++)
           {
               hm[cur^1].init();
               if(maze[i][j])dpblank(i,j,cur);
               else dpblock(i,j,cur);
               cur^=1;
           }
        for(i=0;i<hm[cur].size;i++)
          if(hm[cur].dp[i]>ans)
            ans=hm[cur].dp[i];
        printf("%d\n",ans);
    }
    int main()
    {
      //  freopen("in.txt","r",stdin);
      //  freopen("out.txt","w",stdout);
        int T;
        scanf("%d",&T);
        while(T--)
        {
            init();
            solve();
        }
        return 0;
    }
    
    
    
    /*
    Sample Input
    
    2
    1 1
    10
    1 2
    5 0
    
    Sample Output
    
    10
    5
    
    
    */

     

     

    HDU 4285  circuits   这是天津网络赛的题目。求K个回路的方案数。而且不能是环套环。

    增加个标志位来记录形成的回路个数。而且注意避免环套环的情况。

    解题报告

    http://www.cnblogs.com/kuangbin/archive/2012/10/02/2710308.html

     

    HDU 4285
    /*
    HDU 4285
    要形成刚好K条回路的方法数
    要避免环套环的情况。
    所以形成回路时,要保证两边的插头数是偶数
    
    G++ 11265ms  11820K
    C++ 10656ms  11764K
    
    */
    
    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string.h>
    using namespace std;
    
    const int MAXD=15;
    const int STATE=1000010;
    const int HASH=300007;//这个大一点可以防止TLE,但是容易MLE
    const int MOD=1000000007;
    
    int N,M,K;
    int maze[MAXD][MAXD];
    int code[MAXD];
    int ch[MAXD];
    int num;//圈的个数
    struct HASHMAP
    {
        int head[HASH],next[STATE],size;
        long long state[STATE];
        int f[STATE];
        void init()
        {
            size=0;
            memset(head,-1,sizeof(head));
        }
        void push(long long st,int ans)
        {
            int i;
            int h=st%HASH;
            for(i=head[h];i!=-1;i=next[i])
              if(state[i]==st)
              {
                  f[i]+=ans;
                  f[i]%=MOD;
                  return;
              }
            state[size]=st;
            f[size]=ans;
            next[size]=head[h];
            head[h]=size++;
        }
    }hm[2];
    void decode(int *code,int m,long long  st)
    {
        num=st&63;
        st>>=6;
        for(int i=m;i>=0;i--)
        {
            code[i]=st&7;
            st>>=3;
        }
    }
    long long encode(int *code,int m)//最小表示法
    {
        int cnt=1;
        memset(ch,-1,sizeof(ch));
        ch[0]=0;
        long long st=0;
        for(int i=0;i<=m;i++)
        {
            if(ch[code[i]]==-1)ch[code[i]]=cnt++;
            code[i]=ch[code[i]];
            st<<=3;
            st|=code[i];
        }
        st<<=6;
        st|=num;
        return st;
    }
    void shift(int *code,int m)
    {
        for(int i=m;i>0;i--)code[i]=code[i-1];
        code[0]=0;
    }
    void dpblank(int i,int j,int cur)
    {
        int k,left,up;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            left=code[j-1];
            up=code[j];
            if(left&&up)
            {
                if(left==up)
                {
                    if(num>=K)continue;
                    int t=0;
                    //要避免环套环的情况,需要两边插头数为偶数
                    for(int p=0;p<j-1;p++)
                      if(code[p])t++;
                    if(t&1)continue;
                    if(num<K)
                    {
                        num++;
                        code[j-1]=code[j]=0;
                        hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].f[k]);
                    }
                }
                else
                {
                    code[j-1]=code[j]=0;
                    for(int t=0;t<=M;t++)
                      if(code[t]==up)
                        code[t]=left;
                    hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].f[k]);
                }
            }
            else if(left||up)
            {
                int t;
                if(left)t=left;
                else t=up;
                if(maze[i][j+1])
                {
                    code[j-1]=0;
                    code[j]=t;
                    hm[cur^1].push(encode(code,M),hm[cur].f[k]);
                }
                if(maze[i+1][j])
                {
                    code[j]=0;
                    code[j-1]=t;
                    hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].f[k]);
                }
            }
            else
            {
                if(maze[i][j+1]&&maze[i+1][j])
                {
                    code[j-1]=code[j]=13;
                    hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].f[k]);
                }
            }
        }
    }
    void dpblock(int i,int j,int cur)
    {
        int k;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            code[j-1]=code[j]=0;
            hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].f[k]);
        }
    }
    char str[20];
    void init()
    {
        scanf("%d%d%d",&N,&M,&K);
        memset(maze,0,sizeof(maze));
        for(int i=1;i<=N;i++)
        {
            scanf("%s",&str);
            for(int j=1;j<=M;j++)
              if(str[j-1]=='.')
                maze[i][j]=1;
        }
    }
    void solve()
    {
        int i,j,cur=0;
        hm[cur].init();
        hm[cur].push(0,1);
        for(i=1;i<=N;i++)
          for(j=1;j<=M;j++)
          {
              hm[cur^1].init();
              if(maze[i][j])dpblank(i,j,cur);
              else dpblock(i,j,cur);
              cur^=1;
          }
        int ans=0;
        for(i=0;i<hm[cur].size;i++)
          if(hm[cur].state[i]==K)
          {
              ans+=hm[cur].f[i];
              ans%=MOD;
          }
        printf("%d\n",ans);
    
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        int T;
        scanf("%d",&T);
        while(T--)
        {
            init();
            solve();
        }
        return 0;
    }
    
    /*
    Sample Input
    2
    4 4 1
    **..
    ....
    ....
    ....
    4 4 1
    ....
    ....
    ....
    ....
    
    
    Sample Output
    2
    6
    
    */
    HDU4285
    /*
    HDU  4285
    要形成刚好K条回路的方法数
    要避免环套环的情况。
    所以形成回路时,要保证两边的插头数是偶数
    G++ 11765ms  12560K
    C++  11656ms 12504K
    */
    
    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string.h>
    using namespace std;
    
    const int MAXD=15;
    const int STATE=1000010;
    const int HASH=100007;
    const int MOD=1000000007;
    
    int N,M,K;
    int maze[MAXD][MAXD];
    int code[MAXD];
    int ch[MAXD];
    
    struct HASHMAP
    {
        int head[HASH],next[STATE],size;
        long long state[STATE];
        int f[STATE];
        int cir[STATE];//形成的圈的个数
        void init()
        {
            size=0;
            memset(head,-1,sizeof(head));
        }
        void push(long long st,int ans,int _cir)
        {
            int i,h=st%HASH;
            for(i=head[h];i!=-1;i=next[i])
              if(state[i]==st&&cir[i]==_cir)
              {
                  f[i]+=ans;
                  f[i]%=MOD;
                  return;
              }
            state[size]=st;
            f[size]=ans;
            cir[size]=_cir;
            next[size]=head[h];
            head[h]=size++;
        }
    }hm[2];
    void decode(int *code,int m,long long  st)
    {
        for(int i=m;i>=0;i--)
        {
            code[i]=st&7;
            st>>=3;
        }
    }
    long long encode(int *code,int m)//最小表示法
    {
        int cnt=1;
        memset(ch,-1,sizeof(ch));
        ch[0]=0;
        long long st=0;
        for(int i=0;i<=m;i++)
        {
            if(ch[code[i]]==-1)ch[code[i]]=cnt++;
            code[i]=ch[code[i]];
            st<<=3;
            st|=code[i];
        }
        return st;
    }
    void shift(int *code,int m)
    {
        for(int i=m;i>0;i--)code[i]=code[i-1];
        code[0]=0;
    }
    void dpblank(int i,int j,int cur)
    {
        int k,left,up;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            left=code[j-1];
            up=code[j];
            if(left&&up)
            {
                if(left==up)
                {
                    if(hm[cur].cir[k]>=K)continue;
                    int t=0;
                    for(int p=0;p<j-1;p++)
                      if(code[p])t++;
                    if(t&1)continue;
                    if(hm[cur].cir[k]<K)
                    {
                        code[j-1]=code[j]=0;
                        hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].f[k],hm[cur].cir[k]+1);
                    }
                }
                else
                {
                    code[j-1]=code[j]=0;
                    for(int t=0;t<=M;t++)
                      if(code[t]==up)
                        code[t]=left;
                    hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].f[k],hm[cur].cir[k]);
                }
            }
            else if(left||up)
            {
                int t;
                if(left)t=left;
                else t=up;
                if(maze[i][j+1])
                {
                    code[j-1]=0;
                    code[j]=t;
                    hm[cur^1].push(encode(code,M),hm[cur].f[k],hm[cur].cir[k]);
                }
                if(maze[i+1][j])
                {
                    code[j]=0;
                    code[j-1]=t;
                    hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].f[k],hm[cur].cir[k]);
                }
            }
            else
            {
                if(maze[i][j+1]&&maze[i+1][j])
                {
                    code[j-1]=code[j]=13;
                    hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].f[k],hm[cur].cir[k]);
                }
            }
        }
    }
    void dpblock(int i,int j,int cur)
    {
        int k;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            code[j-1]=code[j]=0;
            hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].f[k],hm[cur].cir[k]);
        }
    }
    char str[20];
    void init()
    {
        scanf("%d%d%d",&N,&M,&K);
        memset(maze,0,sizeof(maze));
        for(int i=1;i<=N;i++)
        {
            scanf("%s",&str);
            for(int j=1;j<=M;j++)
              if(str[j-1]=='.')
                maze[i][j]=1;
        }
    }
    void solve()
    {
        int i,j,cur=0;
        hm[cur].init();
        hm[cur].push(0,1,0);
        for(i=1;i<=N;i++)
          for(j=1;j<=M;j++)
          {
              hm[cur^1].init();
              if(maze[i][j])dpblank(i,j,cur);
              else dpblock(i,j,cur);
              cur^=1;
          }
        int ans=0;
        for(i=0;i<hm[cur].size;i++)
          if(hm[cur].cir[i]==K)
          {
              ans+=hm[cur].f[i];
              ans%=MOD;
          }
        printf("%d\n",ans);
    
    }
    int main()
    {
      //  freopen("in.txt","r",stdin);
     //   freopen("out.txt","w",stdout);
        int T;
        scanf("%d",&T);
        while(T--)
        {
            init();
            solve();
        }
        return 0;
    }
    
    /*
    Sample Input
    2
    4 4 1
    **..
    ....
    ....
    ....
    4 4 1
    ....
    ....
    ....
    ....
    
    
    Sample Output
    2
    6
    
    */

     

     

    上面各题的代码,我都是用一样的模板写的,写的风格都是一致的。插头DP写起来比较难。而且容易写错。更加复杂的插头DP真的很难想到。

    但是插头DP还是很美妙的。更多插头DP的题目等我做了会更新上去的。

    持续更新中......

    2012-10-2   by kuangbin

    人一我百!人十我万!永不放弃~~~怀着自信的心,去追逐梦想
  • 相关阅读:
    心得体悟帖---200130(专业长才(敲门砖))(希望)
    心得体悟帖---200130(一举多的)(少了发自内心的从容)
    范仁义css3课程---19、流动布局
    范仁义css3课程---18、overflow
    日常英语---200130(inspire)
    日常英语---200130(Basketball fans around the world are mourning the death of American superstar Kobe Bryant.)
    视频中的ts文件是什么
    如何美化windows桌面
    心得体悟帖---200127(囚笼-它会推着我的,不必多想)(过好当下,享受当下)
    心得体悟帖---有哪些越早知道越好的人生经验?(转自知乎)
  • 原文地址:https://www.cnblogs.com/kuangbin/p/2710343.html
Copyright © 2020-2023  润新知