zoukankan      html  css  js  c++  java
  • POJ 1038 Bugs Integrated, Inc. (状态dp)

    确实是好题。。。看解题报告看了一天半,才大概明白是怎么样一个过程。最让我纠结的是M,N的行列问题。。。。文字描述里的M,N和图片上的M,N不对应。本菜只能无比蛋疼而又晕晕乎乎的看。。。

    -------------------------------以下部分转自大牛chinaeli-----------------------------------------http://hi.baidu.com/chinaeli/blog/item/b932d4b430d60ac636d3ca34.html

    好了,废话说道这里,我来说说我的想法(其实这个方法都是大家用的,我也是效仿别人的方法)
    首先说一下如何用三进制表示状态:


    假设现在考虑(m,i),从而推出(m,i+1)的状态,因此我们需要记录第i列以及第i-1列的状态,用三进制表示的方法就是A(用0表示),B(用1表示),C(用2表示),其中虚线部分为第i+1列(这个图片旋转90度比较好,做图片时粗心了,嘻嘻),C状态中,因为假如第i列不能放,那么自然第i-1列放和不放都无关紧要了,所以用灰色表示。用p(m)表示第m行,第i列和第i-1列的状态,那么整个的放置状态就是p(0)*3^0+p(1)*3^1......p(M-1)*3^(M-1),转成10进制存储。
    状态表示完之后,就要进行状态转移了。


    M位的三进制共有3^M种状态,( 0<M<=10),因此最大有59049种状态,采用滚动数组,只要开一个2*59049大小的二维数组就可以了。将边界条件f[0][3^M-1]=0,其余初始为-1,表示该状态不可到达或者尚未到达。然后从第0行开始考虑,枚举每行的状态( 从0到3^M-1 ) ,用s表示,将10进制数转换成3进制存在一个p数组中,接着需要产生一个新的状态,也就是第i+1列的状态:

    由于下移了一列,第i-1列我们暂不考虑,之前的A状态变成了A',B变成了B',C变成了C’,之前的0和1都变成新状态的0,原来的2状态变成了新状态的1,但是需要考虑的是第i+1列中是否会存在不能放的区域,假如上图的某个问号中某处不能放置东西,那么不论这个状态是0,还是1,都将变成2,将新状态存于q数组中。现在新生成的状态t是在第i+1行不放置任何东西的状态,那么自然f[i+1][t]=f[i][s].

    现在就要进入关键的部分了,用dfs搜索各种摆放的状态。

    假设现在枚举到(m,n),目前状态是s,目前已经摆放了cnt个芯片。


    如果m<M-2,说明还有至少3列的空处,可以摆放A方式的芯片,但是必须满足(m,n),(m,n-1),(m+1,n),(m+1,n-1),(m+2,n),(m+2,n-1)处空白,也就是q[m]==0 && q[m+1]==0&& q[m+2]==0.那么将状态修改为s=s+2*3^m+2*3^(m+1)+2*3^(m+2)。同理进行B方式的摆放,不过在摆放B时,需要考虑到第n-2行,所以要保证p[m]==0,p[m+1]==0。
    当然这一格也可以不摆放。

     

     

     

     

    View Code
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #define Max(a,b) (a>b?a:b)
    #define N 59050
    //三进制
    int tri[12]={0,1,3,9,27,81,243,729,2187,6561,19683,59049};
    int map[151][11];
    int dp[2][N];
    //前一状态,当前状态
    int info_pre[11],info_cur[11];
    int n,m,pass;
    //初始化
    void Init()
    {
        memset(map,0,sizeof(map));
        memset(dp,-1,sizeof(dp));
    }
    //转化 十进制
    int switch_ten(int *p)
    {
        int i,ans;
        for(i=1,ans=0;i<=m;i++){
            ans += p[i]*tri[i];
        }
        return ans;
    }
    //转化 三进制
    void switch_tri(int t,int *p)
    {
        int i;
        for(i=1;i<=m;i++){
            p[i] = t%3;
            t/=3;
        }
        return ;
    }
    void dfs(int i,int j,int cnt,int stata)
    {
        int k;
        dp[i%2][stata] = Max(dp[i%2][stata],cnt);
        if(j >= m ) return ;
        if(!info_pre[j] && !info_pre[j+1] && !info_cur[j] && !info_cur[j+1]){
            // 3*2 排列时 
            info_cur[j] = info_cur[j+1] = 2;
            k = switch_ten(info_cur);
            dfs(i,j+2,cnt+1,k);
            info_cur[j]=info_cur[j+1]=0;
        }
        if(j < m-1 && !info_cur[j] && !info_cur[j+1] && !info_cur[j+2]){
            // 2*3 排列时
            info_cur[j] = info_cur[j+1] = info_cur[j+2] = 2;
            k = switch_ten(info_cur);
            dfs(i,j+3,cnt+1,k);
            info_cur[j] = info_cur[j+1] = info_cur[j+2] = 0;
        }
        dfs(i,j+1,cnt,stata);
        return ;
    }
    int main()
    {
    
        int t,k,i,j,l,stata,ans;
        scanf("%d",&t);
        while(t--){    
            Init();
            scanf("%d%d%d",&n,&m,&k);
            while(k--){
                scanf("%d%d",&i,&j);
                map[i][j] = 1;
            }
            for(i=1;i<=m;i++){
                info_pre[i] = map[1][i] + 1;
            }
            stata = switch_ten(info_pre);
            dp[1][stata] = 0;
            for(i=2;i<=n;i++){
    
                for(j=0;j<tri[m+1];j++)dp[i%2][j] = -1;
            
                for(j=0;j<tri[m+1];j++){
                    
                    if(dp[(i+1)%2][j] == -1)continue;
                
                    switch_tri(j,info_pre);
                
                    for(l=1;l<=m;l++){
                        if(map[i][l])
                            info_cur[l] = 2;
                        else info_cur[l] = Max(info_pre[l]-1,0);
                    }
                    pass = dp[(i+1)%2][j];
                    dfs(i,1,pass,switch_ten(info_cur));
                }
            }
            for(i=0,ans=0;i<tri[m+1];i++){
                ans = Max(ans,dp[n%2][i]);
            }
            printf("%d\n",ans);
        
        }
        return 0;
    }

     

     

     

  • 相关阅读:
    xml实现AOP
    AOP
    python 大小写转换方法(全)
    vs2013 快捷键
    构造方法后面带:this()
    资源的使用----实例分析
    把列表变成用指定字符连接的字符串
    python 列表、元组操作
    工作踩坑记录:JavaScript跳转被缓存
    《Effective Java》读书笔记
  • 原文地址:https://www.cnblogs.com/vongang/p/2615322.html
Copyright © 2011-2022 走看看