POJ 3654 Corn Fields 状态压缩

最近我总是辗转反侧,难以入眠,对我们曾有过的愿景,浮想联翩。但亲爱的,我早已在内心深处祈祷着,祈祷自己不再迷失于金钱的追逐中。

ok,刷动态规划题。
题意如下:
N行M列
一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相邻。问有多少种放牛方案(一头牛都不放也是一种方案)N,M范围不超过12。
Sample Input

2 3
1 1 1
0 1 0
Sample Output

9
数据解释:
将数据看为
1 2 3
0 4 0
则可行方案有(1),(2),(3),(4),(1 ,3),(1,4),(3,4),(1,3,4),()空表示什么也不放。
这道题很明显是状态压缩,因为N和M范围就可以明显看出来了。
怎么设计状态呢。
我们用dp[i][j]表示i行j状态可行的最大方案。
那么下一行dp[i+1][j]就应该为上一行所有可行方案的和。
即dp[i+1][j]= sigma (dp[i][k])k应为可行的方案。
详细介绍请看代码。

#include "cstdio"
using namespace std;
const int mod = 100000000;
int n, m, state[600], top, dp[13][600], a, cur[13], ans;//state数组存储单行中合法状态(即没有两只牛在一起的状态),dp[i][j]表示第i行state[j]状态可获得最大方案。cur[i]来存储第i行中的0(若第j个为0则给那一位打上1)
bool ok( int x ) {
    if ( x & (x<<1) ) return 0;//判断单行中合法状态即初始化state
    return 1;
}
bool fit( int x, int i ) {//判断上下两行状态合不合法(也可用于与cur判断)
    if ( x & i ) return 0;
    else return 1;
}
int main() {
    scanf( "%d%d", &n, &m );
    for ( int i = 1; i <= n; i++ )
        for ( int j = 1; j <= m; j++ ) {
            scanf( "%d", &a );
            if ( a == 0 ) cur[i] += (1<<(m-j));
        }
    int zt = (1<<m)-1;
    for ( int j = 0; j <= zt; j++ )
        if ( ok(j) ) state[++top] = j;
    for ( int j = 1; j <= top; j++ )
        if ( fit(state[j], cur[1]) ) dp[1][j] = 1;
    for ( int i = 2; i <= n; i++ )
        for ( int j = 1; j <= top; j++ )
            if ( fit(state[j], cur[i-1]) )
                for ( int k = 1; k <= top; k++ )
                    if ( fit(state[k], cur[i]) && fit(state[k], state[j]) )
                        dp[i][k] = (dp[i][k] + dp[i-1][j]) % mod;//状态转移加上上一行的所有可行方案
    for ( int j = 1; j <= top; j++ )
        ans = (ans + dp[n][j]) % mod;//答案都在最后一行
    printf( "%d\n", ans );
    return 0;
}

最后附上我对你的思念。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值