• 插头DP学习


    队内没人会插头DP,感觉这个不会不行。。。所以我还是默默去学了一下,

    学了一天,感觉会了一点。对于每一行,一共有j+1个插头,如果是多回路类的题目,

    比较简单,可以用1表示有插头,0表示没有插头,这样就可以愉快转移了,

    对于当前出来的位置(i,j),与它有关的插头有j-1和j 那么我们可以枚举状态经行转移。

    对于单回路的问题。。。。只是了解思想,目前还不会写,太笨了=_=

    poj 2411 Mondriaan's Dream

    题意:用1*2小方块组成n*m矩阵有多少种组成方式

    思路:我们从上到下处理每一行,对于当前处理的位置 (i,j),枚举它的插头状态,0~(1<<(m+1));

    假设状态是 sta,如果sta表示的状态没有j-1和j 插头(即(sta&(1<<(j-1))) == 0 &&(sta&(1<<j)) == 0)

    那么转移到它的状态有两种,j-1插头有或者j插头存在,

    如果sta表示的状态都有j-1和j 插头,这样状态是不合法的,直接=0

    如果sta表示的状态j 插头,表示是平放方块,这个状态只能由j-1,j插头不存在状态转移过来

    如果sta表示的状态j-1 插头,表示是竖放方块,这个状态只能由j-1,j插头不存在状态转移过来

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<set>
    #include<stack>
    #include<map>
    #include<ctime>
    #include<bitset>
    #define LL long long
    #define INF 999999
    #define maxn 200001
    #define mod 1000000007
    #define INF 0x3f3f3f3f
    using namespace std;
    
    int mat[15][15];
    LL dp[12][12][(1<<13)+10] ;
    
    int main()
    {
        int i , n ,m , j, k ,case1=0;
        int len , T ,x ,y ,sta ;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            if(n+m==0)break ;
            if((n*m)&1)
            {
                puts("0") ;
                continue ;
            }
            memset(dp,0,sizeof(dp)) ;
            len=(1<<(m+1));
            dp[0][m][0]=1;
            for( i = 1 ; i <= n ;i++)
            {
                for( j = 0 ; j < len ;j++)
                    dp[i][0][(j<<1)]=dp[i-1][m][j] ;
                for( k = 1 ; k <= m ;k++)
                {
                    for( sta = 0 ; sta < len ;sta++)
                    {
                        y = (1<<k) ;
                        x = (1<<(k-1)) ;
                        if((sta&x) != 0 &&(sta&y) != 0 )
                        {
                            dp[i][k][sta]=0;
                        }
                        else if((sta&x)==0&&0==(sta&y))
                        {
                            dp[i][k][sta]=dp[i][k-1][sta^x]+dp[i][k-1][sta^y] ;
                        }
                        else if((sta&x))
                            dp[i][k][sta]=dp[i][k-1][sta^x];
                        else dp[i][k][sta]=dp[i][k-1][sta^y];
                    }
                }
            }
            printf("%I64d
    ",dp[n][m][0]);
        }
        return 0 ;
    }
    View Code

    hdu 4804 Campus Design

    题意:和上题差不多,多了的东西是,有些地方不能放方块,

    还有可以放1*1方块,求的是 1*1放的个数限制在c-d内的放的方式有多少种

    思路:具体做法和上面也是差不多,

    差别:对于1*1放置个数的限制,我们可以开多一维记录1*1用的个数,

    对于不能放置的位置(i,j ),合法的状态sta,里面不能有 j-1,j 插头

    对于可以放置的位置(1,j) ,状态是 sta,如果sta表示的状态没有j-1和j 插头时

    多了一步转移,就是 放置1*1的状态。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<set>
    #include<stack>
    #include<map>
    #include<ctime>
    #include<bitset>
    #define LL long long
    #define INF 999999
    #define maxn 200001
    #define mod 1000000007
    #define INF 0x3f3f3f3f
    using namespace std;
    
    char mat[105][25];
    int dp[2][12][22][(1<<12)+10];
    
    int main()
    {
        int i , n ,m , j, k ,case1=0;
        int len , T ,x ,y ,sta,c,d ,v ;
        int now,pre;
        while(scanf("%d%d%d%d",&n,&m,&c,&d )!=EOF)
        {
            for( i = 1 ; i <= n ;i++)
               scanf("%s",mat[i]+1);
            memset(dp,0,sizeof(dp)) ;
            len=(1<<(m+1));
            dp[0][m][0][0]=1;
            pre=1;
            now=0;
            for( i = 1 ; i <= n ;i++)
            {
                swap(pre,now);
              //  memset(dp[now],0,sizeof(dp[now])) ;
                for( v = 0 ; v <= d ;v++ )
                   for( j = 0 ; j < len ;j++)
                     dp[now][0][v][(j<<1)]=dp[pre][m][v][j] ;
                for( k = 1 ; k <= m ;k++)
                {
                    y = (1<<k) ;
                    x = (1<<(k-1)) ;
                    for( v = 0 ; v <= d ;v++ )
                        for( sta = 0 ; sta < len ;sta++)
                        {
                                 if(mat[i][k]=='0')
                                 {
                                     if((sta&x)||(sta&y))
                                     {
                                         dp[now][k][v][sta]=0;
                                     }
                                     else dp[now][k][v][sta]=dp[now][k-1][v][sta] ;
                                 }
                                 else{
                                    if((sta&x) != 0 &&(sta&y) != 0 )
                                    {
                                        dp[now][k][v][sta]=0;
                                    }
                                    else if((sta&x) == 0 &&(sta&y) == 0 )
                                    {
                                        dp[now][k][v][sta]=(dp[now][k-1][v][sta^x]+dp[now][k-1][v][sta^y])%mod ;
                                        if(v>0)dp[now][k][v][sta]=(dp[now][k][v][sta]+dp[now][k-1][v-1][sta])%mod ;
                                    }
                                    else if((sta&x))
                                      dp[now][k][v][sta]=dp[now][k-1][v][sta^x];
                                    else dp[now][k][v][sta]=dp[now][k-1][v][sta^y];
                                 }
                        }
                }
            }
            int ans1=0;
            for( i = c ; i <= d;i++)
                ans1=(ans1+dp[now][m][i][0])%mod;
            printf("%d
    ",ans1);
        }
        return 0 ;
    }
    View Code

    hdu 1693 Eat the Trees

    题意:在n*m的矩阵中,有些格子有树,没有树的格子不能到达,找一条或多条回路,吃完所有的树,求有多少中方法。

    思路:看这个博客吧,here

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<set>
    #include<stack>
    #include<map>
    #include<ctime>
    #include<bitset>
    #define LL long long
    #define INF 999999
    #define maxn 200001
    #define mod 1000000007
    #define INF 0x3f3f3f3f
    using namespace std;
    
    int mat[15][15];
    LL dp[12][12][(1<<13)+10] ;
    
    int main()
    {
        int i , n ,m , j, k ,case1=0;
        int len , T ,x ,y ,sta ;
        cin >>T ;
        while(T--)
        {
            scanf("%d%d",&n,&m) ;
            for( i = 1 ; i <= n ;i++)
               for( j = 1 ; j <= m ;j++)
                 scanf("%d",&mat[i][j]);
            memset(dp,0,sizeof(dp)) ;
            len=(1<<(m+1));
            dp[0][m][0]=1;
            for( i = 1 ; i <= n ;i++)
            {
                for( j = 0 ; j < len ;j++)
                    dp[i][0][(j<<1)]=dp[i-1][m][j] ;
                for( k = 1 ; k <= m ;k++)
                {
                    for( sta = 0 ; sta < len ;sta++)
                    {
                        y = (1<<k) ;
                        x = (1<<(k-1)) ;
                        if(mat[i][k])
                        {
                            if((sta&x) && (sta&y))
                                dp[i][k][sta]=dp[i][k-1][sta^x^y] ;
                            else if((sta&x)==0 && 0== (sta&y))
                                dp[i][k][sta]=dp[i][k-1][sta^x^y] ;
                            else dp[i][k][sta]=dp[i][k-1][sta^x^y]+dp[i][k-1][sta] ;
                        }
                        else
                        {
                            if((sta&x)==0&&(sta&y)==0)
                                dp[i][k][sta]=dp[i][k-1][sta] ;
                            else dp[i][k][sta]=0;
                        }
                    }
                }
            }
            printf("Case %d: ",++case1);
             printf("There are %I64d ways to eat the trees.
    ",dp[n][m][0]);
        }
        return 0 ;
    }
    View Code
  • 相关阅读:
    .net验证是否合法邮箱和ip地址的方式
    .net通用类型转换方法
    asp.net中的<%%>的使用
    autofac初识
    .net面试题
    asp.net使用一般处理程序实现文件下载
    asp.net 一般处理程序接收上传文件的问题
    Python学习日记(十八) 序列化模块
    Python学习日记(十七) os模块和sys模块
    Python学习日记(十六) time模块和random模块
  • 原文地址:https://www.cnblogs.com/20120125llcai/p/4049538.html
Copyright © 2020-2023  润新知