poj1185 炮兵阵地 状态压缩dp 算法竞赛进阶指南例题

炮兵阵地
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 31074 Accepted: 11978

Description

司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 

如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。 
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。 

Input

第一行包含两个由空格分割开的正整数,分别表示N和M; 
接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。

Output

仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

Sample Input

5 4
PHPP
PPHH
PPPP
PHPP
PHHP

Sample Output

6

Source

/**
 * @Author:      H S-J
 * @DateTime:    2018-04-18 20:10:21
 * @Description: 
 */
// #include <bits/stdc++.h>
#include <iostream>
#include <cstring>
using namespace std;
#define MST(a, b) memset(a, b, sizeof(a));
#define CLR(a) MST(a, 0);
#define DBG(x) cout << '#' << " = " << (x) << endl;
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x.begin())
#define lson(x) (x) << 1
#define rson(x) (x) << 1|1
#define pb push_back
#define rep(x, y, z) for (int x = y; x < z; ++x)
#define dwn(x, y, z) for (int x = y; x >= z; --x)
#define ech(x, y, z) for (auto x = z.begin(), y = z.end(); x != y; ++x)
#define lowbit(x) (x & (-x))
#define opr operator
#define _st first
#define _nd second
typedef long long LL;
typedef stringstream strstm;
const double PI = 3.1415926535898;
const double E = 2.718281828459;
const int INF = 0x3f3f3f3f;
int dp[101][77][77];
int sg[101];
int n, m, idx;
int s[77]; //合法摆放的集合
int cnt0[77]; //合法摆放方案的具体摆放个数, 即二进制下1的个数
int get_one(int x) {
	int cnt = 0;
	while(x) x &= (x-1), ++cnt;
	return cnt;
}
bool ok(int x) {
	// 相邻两个P之间要有两个H
	if(x & (x << 1)) return false;
	if(x & (x << 2)) return false;
	return true;
}
void init() {
	idx = 0;
	int end = 1 << m;
	rep(i, 0, end) if(ok(i)) {
		// s保存合法方案的集合
		s[idx] = i;
		// cnt0保存合法方案的摆放个数, 二进制位1的个数
		cnt0[idx++] = get_one(i);
	}
}
bool valid(int i, int x) {
	if(sg[i] & x) return false;
	return true;
}
int solve() {
	int ans = 0;
	MST(dp, -1);
	dp[0][0][0] = 0;
	rep(j, 0, idx) if(valid(1, s[j])) {
		dp[1][j][0] = cnt0[j];
		// 考虑n==1情况
		ans = max(ans, dp[1][j][0]);
	}
	rep(i, 2, n+1) {
		// valid()函数判断, 第i行, 用方案s[j]是否合法
		rep(j, 0, idx) if(valid(i, s[j])) {
			// i行跟i-1行的方案, 满足, 互相炸不到对方
			rep(k, 0, idx) if(valid(i-1, s[k]) && (s[j]&s[k])==0) {
				int last = 0;
				rep(l, 0, idx) if(dp[i-1][k][l] != -1 && (s[l]&s[j])==0 && valid(i-2, s[l])) {
					last = max(last, dp[i-1][k][l]);
				}
				dp[i][j][k] = max(dp[i][j][k], last + cnt0[j]);
				if(i == n) ans = max(ans, dp[i][j][k]);
			}
		}
	}
	return ans;
}
int main(int argc, char const *argv[]) {
	ios::sync_with_stdio(0);cin.tie(0);
	cin >> n >> m;
	rep(i, 1, n+1) rep(j, 0, m) {
		char tmp; cin >> tmp;
		if(tmp == 'H') sg[i] |= (1 << (m-1-j));
	}
	init();
	cout << solve() << endl;
	return 0;
}

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值