lightoj 1092 状态压缩DP

WA了好久

主要是在一维的情况的时候,我直接判断是否是全*,错误的任务非全*是不可能变全*的。。。。orz 原谅我蒟蒻

dp【i】【st1】【st2】表示操作完第i行后第i行状态为st1 第i+1行状态为st2

然后枚举找出所有能使st1为0的opt来向后更新

AC代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

#define MAX 0x3f3f3f3f

int R, C;
int dp[10][1<<8][1<<8];
int statu[10];
char maps[10][10];

int st_opt[1<<8][1<<8];
int cnt_opt[1<<8];

int getst( int st, int opt ){
    int ans = st;
    for( int i = 0; i < C; i++ ){
        if( opt & ( 1 << i ) ){

            if( i > 0 ) ans ^= ( 1 << ( i - 1 ) );
            ans ^= ( 1 << ( i ) );
            if( i < C - 1 ) ans ^= ( 1 << ( i + 1 ) );
        }
    }
    return ans;
}

int getcnt( int opt ){
    int ans = 0;
    for( int i = 0; i < C; i++ ){
        if( opt & ( 1 << i ) ){
            ans++;
        }
    }
    return ans;
}

void init(){
    for( int i = 0; i < ( 1 << C ); i++ ){
        for( int j = 0; j < ( 1 << C ); j++ ){
            st_opt[i][j] = getst( i, j );
        }
    }
    for( int i = 0; i < ( 1 << C ); i++ ){
        cnt_opt[i] = getcnt( i );
    }
}

int main(){
    int T, Case = 1;

    scanf( "%d", &T );
    while( T-- ){
        scanf( "%d%d", &R, &C );
        init();
        for( int i = 0; i < R; i++ ){
            scanf( "%s", maps[i] );
            statu[i] = 0;
            for( int j = 0; j < C; j++ ){
                if( maps[i][j] == '.' ){
                    statu[i] |= ( 1 << j );
                }
            }
        }
        int ans = MAX;
        if( R == 1){
            for( int opt = 0; opt < ( 1 << C ); opt++ ){
                if( st_opt[statu[0]][opt] == 0 ){
                    ans = min( ans, cnt_opt[opt] );
                }
            }
        }else{
            memset( dp, 0x3f, sizeof( dp ) );

            dp[0][statu[0]][statu[1]] = 0;
            for( int opt = 0; opt < ( 1 << C ); opt++ ){
                dp[0][st_opt[statu[0]][opt]][st_opt[statu[1]][opt]] = min( dp[0][st_opt[statu[0]][opt]][st_opt[statu[1]][opt]],
                                                                          cnt_opt[opt] ) ;
            }
            for( int i = 0; i < R - 2; i++ ){
                for( int st1 = 0; st1 < ( 1 << C ); st1++ ){
                    for( int st2 = 0; st2 < ( 1 << C ); st2++ ){
                        if( dp[i][st1][st2] != MAX ){
                            for( int opt = 0; opt < ( 1 << C ); opt++ ){
                                if( st_opt[st1][opt] == 0 ){
                                    dp[i+1][st_opt[st2][opt]][st_opt[statu[i+2]][opt]] = min( dp[i][st1][st2] + cnt_opt[opt],
                                                                                             dp[i+1][st_opt[st2][opt]][st_opt[statu[i+2]][opt]] );
                                }
                            }
                        }
                    }
                }
            }
            for( int st1 = 0; st1 < ( 1 << C ); st1++ ){
                for( int st2 = 0; st2 < ( 1 << C ); st2++ ){
                    if( dp[R-2][st1][st2] != MAX ){
                        for( int opt = 0; opt < ( 1 << C ); opt++ ){
                            if( st_opt[st1][opt] == 0 && st_opt[st2][opt] == 0 ){
                                ans = min( ans, dp[R-2][st1][st2] + cnt_opt[opt] );
                            }
                        }
                    }
                }
            }
        }
        printf( "Case %d: ", Case++ );
        if( ans != MAX ){
            printf( "%d\n", ans );
        }else{
            printf( "impossible\n" );
        }
    }
    return 0;
}
/*
100
5 5
*****
*...*
*...*
*...*
*****
1 2
.*
3 3
**.
**.
...
4 4
*...
**..
..**
...*
8 8
********
********
********
********
********
********
********
********
8 8
........
........
........
........
........
........
........
........
8 8
********
********
********
***.****
****.***
***.****
********
*****.**
1 5
..***
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值