读题干发现(前两个点不容易想明白)
- 可以把每一行的坦克分布情况通过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;
}