状态压缩dp

POJ1185

读题干发现(前两个点不容易想明白)

  • 可以把每一行的坦克分布情况通过0、1来表示,并将这一串01的串表示为一个状态,存放在一个status数组中(这个数组最多有60个元素,具体解释见参考博客,然后此时可以将所有可能存在的状态放进来,就是不管地图的山地还是平地情况,只要这一行的状态就只能从这六十个里边挑) 注意这个满足状态挑选的方法:(i&(i<<1)) == 0 && (i&(i<<2)) == 0
  • 然后对于一行中的这将近60中状态要看摆放了多少坦克,cnt数组就是用来计算这种状态下这一行所摆放的坦克数量
    遍历方法:
tem = status[i],temcnt = 0;
        while (tem) {
            tem &= (tem-1);
            cnt[i]++;
        }
  • 然后开始按行数开始遍历,内部套三层的循环来匹配相应的状态。(注意要考虑的是三行)
//
//  main.cpp
//  状态压缩dp_板题_m
//
//  Created by 陈冉飞 on 2019/8/5.
//  Copyright © 2019 陈冉飞. All rights reserved.
//

#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#define maxn 105
typedef long long ll;
#define cl(a,b) memset(a,b,sizeof(a))

using namespace std;
int base[maxn];    //将每一行的数据压缩储存在一个向量中
//int status[maxn];
int cnt[maxn];
vector<int>status;
int dp[105][70][70];
int n,m,ans;//地图的大小

int main(int argc, const char * argv[]) {
    ans = 0;
    scanf("%d%d",&n,&m);
    cl(dp, 0);
    cl(base, 0);
    string temstr;
    int i,j,k,temcnt,tem;
    for (i = 0; i < n; i++) {
        cin>>temstr;
        temcnt = 0;
        for (j = 0; j < m; j++) {
            //H为山地,要把山地的(这种特殊的位置)储存起来
            if (temstr[j] == 'H') {
                temcnt |= (1<<j);
            }
        }
        base[i] = temcnt;
    }
    //然后提取所有的状态
    for (i = 0; i < (1<<m); i++) {
        if ((i&(i<<1)) == 0 && (i&(i<<2)) == 0) {     //此时i所满足的状态即可
            status.push_back(i);
        }
    }
    //然后再计算每种状态下所含有的数量     也就是此时这一行所含有的一的数量,一为放坦克,二为不放坦克
    for (i = 0; i < status.size(); i++) {
        tem = status[i],temcnt = 0;
        while (tem) {
            tem &= (tem-1);
            cnt[i]++;
        }
    }
    
    //初始化部分  后面遍历是从第三行开始遍历
    for (i = 0; i < status.size(); i++) {
        if ((status[i] & base[0]) == 0) {
            dp[0][i][0] = cnt[i];
        }
    }
    for (i = 0; i < status.size(); i++) {
        if ((status[i] & base[1]) == 0) {
            for (j = 0; j <  status.size(); j++) {
                if (status[j] & base[0]) continue;
                if (status[i] & status[j]) continue;
                dp[1][i][j] = dp[0][j][0]+cnt[i];
            }
        }
    }
    
    //开始三层遍历,题目要求上面的两层都是符合的  要从第三行开始遍历
    for (int r = 2; r < n; r++) {
        for (i = 0; i < status.size(); i++) {
            if (status[i] & base[r]) continue;
            for (j = 0; j < status.size(); j++) {
                if (status[j] & base[r-1]) continue;
                if (status[i] & status[j]) continue;
                for (k = 0; k < status.size(); k++) {
                    if (status[k] & base[r-2]) continue;
                    if (status[i] & status[k]) continue;
                    if (status[j] & status[k]) continue;
                    dp[r][i][j] = max(dp[r][i][j], dp[r-1][j][k]+cnt[i]);
                }
            }
        }
    }
    for (i = 0; i < status.size(); i++) {
        for (j = 0; j < status.size(); j++) {
            ans = max(ans,dp[n-1][i][j]);
        }
    }
    cout<<ans<<endl;
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值