POJ 1185 NOI 2001 炮兵阵地 状压DP

来源:互联网 发布:edf调度算法源代码 编辑:程序博客网 时间:2024/06/06 09:42

题目大意:给出一个地图,有两种点,P点可以站人,H点不能站人。每放一个人就会对他上下左右各两个格子产生影响,产生影响的格子不能放人。问最多能放多少个人。


思路:数据范围指引解题的方向。题中给出M<=10,这是一个很小的数字,2^10也不过才1024,用这个来dp就轻松多了。于是我们先预处理出每一行可能出现的状态,要注意一行中不能有两个距离<2。大表之后发现,每一行最多只能有60个左右。现在可以放心做O(n^3×m)的dp了。处理上下几行的关系的时候要注意status&status_==0时才能转移。

最后是如果m<=2的时候要特判,直接从状态中找一个最大值输出就可以。


CODE:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;int m,n;char src[110][110];int status[110][1500];int num[1500];int f[110][110][110];void Pretreatment(){for(int i = 1; i <= (1 << n); ++i)num[i] = num[i >> 1] + (i&1);}inline bool Judge(int x,int status){static bool v[110];memset(v,false,sizeof(v));int p = 0;while(status) {v[p++] = status&1;status >>= 1;}for(int i = 0; i < n; ++i)if(v[i]) {if(src[x][i] == 'H')return false;if(v[i - 1] || v[i - 2])return false;}return true;}int main(){cin >> m >> n;Pretreatment();for(int i = 1; i <= m; ++i)scanf("%s",src[i]);for(int i = 1; i <= m; ++i)for(int j = 0; j < (1 << n); ++j)if(Judge(i,j))status[i][++status[i][0]] = j;for(int j = 1; j <= status[2][0]; ++j)for(int i = 1; i <= status[1][0]; ++i)if((status[1][i]&status[2][j]) == 0)f[2][j][i] = max(f[2][j][i],num[status[1][i]] + num[status[2][j]]);if(m == 1 || m == 2) {int ans = 0;for(int i = 1; i <= status[1][0]; ++i)ans = max(ans,num[status[1][i]]);for(int i = 1; i <= status[2][0]; ++i)ans = max(ans,num[status[2][i]]);cout << ans << endl;return 0;}int ans = 0;for(int i = 3; i <= m; ++i)for(int j = 1; j <= status[i][0]; ++j)for(int k = 1; k <= status[i - 1][0]; ++k)for(int l = 1; l <= status[i - 2][0]; ++l) {if((status[i][j]&status[i - 1][k]) || (status[i - 1][k]&status[i - 2][l]) || (status[i][j]&status[i - 2][l]))continue;f[i][j][k] = max(f[i][j][k],f[i - 1][k][l] + num[status[i][j]]);ans = max(ans,f[i][j][k]);}cout << ans << endl;return 0;}


0 0