hdu 4529 状态压缩DP

按行来递推

在递推的过程中每一行的状态与前两行的状态有关,所以要记录上两行的状态,然后用上两行的状态搜出所有可能的新的两行的状态

和那个炮兵阵地是一样的

AC代码如下:

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

__int64 dp[2][11][1<<8][1<<8];
char maps[10][10];
int N;
int now, pre;
int ttt[10];
int nowi;

void DFS( int pos, int num, int st1, int st2, int cnt ){
    if( pos >= 8 ){
        int new_st = 0;
        for( int i = 0; i < 8; i++ ){
            if( ttt[i] == 1 ){
                new_st |= ( 1 << i );
            }
        }
        dp[now][num][new_st][st1] += cnt;
        return;
    }
    ttt[pos] = 0;
    DFS( pos + 1, num, st1, st2, cnt );
    if( num > 0 && maps[nowi][pos] != '*' && !(  ( ( st2 & (1<<(pos-1)) ) && pos >= 1 ) || ( ( st2 & (1<<(pos+1)) ) && pos < 7 ) )
       && !(  ( ( st1 & (1<<(pos-2)) ) && pos >= 2 ) || ( ( st1 & (1<<(pos+2)) ) && pos < 6 ) )  ){
        ttt[pos] = 1;
        DFS( pos + 1, num - 1, st1, st2, cnt );
        ttt[pos] = 0;
    }
}

int main(){
    int T;

    scanf( "%d", &T );
    while( T-- ){
        scanf( "%d", &N );
        for( int i = 0; i < 8; i++ ){
            scanf( "%s", maps[i] );
        }
        now = 0, pre = 1;
        memset( dp, 0, sizeof( dp ) );
        dp[now][N][0][0] = 1;
        for( int i = 0; i < 8; i++ ){
            nowi = i;
            swap( now, pre );
            memset( dp[now], 0, sizeof( dp[now] ) );
            for( int j = 0; j <= N; j++ ){
                for( int k = 0; k < ( 1 << 8 ); k++ ){
                    for( int l = 0; l < ( 1 << 8 ); l++ ){
                        if( dp[pre][j][k][l] != 0 ){
                            DFS( 0, j, k, l, dp[pre][j][k][l] );
                        }
                    }
                }
            }
        }
        __int64 ans = 0;
        for( int i = 0; i < ( 1 << 8 ); i++ ){
            for( int j = 0; j < ( 1 << 8 ); j++ ){
                ans += dp[now][0][i][j];
            }
        }
        printf( "%I64d\n", ans );
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值