题目大意:给出一个地图,有两种点,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; }
原文地址:http://blog.csdn.net/jiangyuze831/article/details/40618363