Description
Input
Output
Sample Input
2 6 6 5 1 4 4 6 2 2 3 6 6 4 6 5 4 3 3 6 1 6 2 6 4
Sample Output
3 4
思路:
1. 允许的内存为 30000K, 需要使用滚动数组
2. dp[row][state], row 实际取值只有0,1, 使用滚动数组递推, 表示 row, row-1 行的状态为 state 时的最优解(最多的矩形数)
state 一个变量就标出来两行的状态
3. dp[row][state] 由 row, row-1, row-2 三行决定.
<1> row 行的 l 列不可以是坏点
<2> 若是 3*2 的摆放方式, 则 row-1 行, row-2 行, l, l+1, 列不可以被占据
<3> 若是 2*3 ...
void dfs(const int &row, const int &pos, const int &maxNum, const int &s) { dp[row%2][s] = max(dp[row%2][s], maxNum); // 继承 if(pos >= M) return; // 步长不是1, 所以 == 不行 if(pos<M && !stateCur[pos] && !stateCur[pos+1] && !statePre[pos] && !statePre[pos+1]) { // 3*2 的矩形 stateCur[pos] = stateCur[pos+1] = 2; // 对下一层来讲, 只需要 stateCur int k = tri2Ten(stateCur); dfs(row, pos+2, maxNum+1, k); stateCur[pos] = stateCur[pos+1] = 0; // 还原 } if(pos<M-1 && !stateCur[pos] && !stateCur[pos+1] && !stateCur[pos+2]) { stateCur[pos] = stateCur[pos+1] = stateCur[pos+3] = 2; int k = tri2Ten(stateCur); dfs(row, pos+3, maxNum+1, k); stateCur[pos] = stateCur[pos+1] = stateCur[pos+3] = 0; } dfs(row, pos+1, maxNum, s); }
总结:
1. map[0] 可初始化为全部被占据. 并且, 这也不需要显式赋值, 只需
for(int i = 0; i <= M; i ++) statePre[i] = map[1][i] + 1;
2. 代码中的 dfs 函数很是精髓. row 是可以当做全局变量, 不需要显式的当做参数. pos 和 maxNum 是必须的, s 主要是为了更新 dp[row%2][s]
3. 最后一步 ans = max(ans, dp[row%2][i]), 可以通过观察发现 row%2 总是最后一行
代码:
#include <iostream> using namespace std; const int MAXN = 60000; int tri[12]={0,1,3,9,27,81,243,729,2187,6561,19683,59049}; // 三进制 int testCase, N, M, K; int statePre[11], stateCur[11]; int map[160][11]; int dp[2][MAXN]; void ten2Tri(int j) { memset(statePre, 0, sizeof(statePre)); for(int i = 1; i <= M && j; i ++) { statePre[i] = j % 3; j /= 3; } } int tri2Ten(const int *p) { int ans = 0; for(int i = 1; i <= M; i ++) { ans += (p[i]*tri[i]); } return ans; } void pre_process() { memset(statePre, 0, sizeof(statePre)); memset(stateCur, 0, sizeof(stateCur)); // 初始化第一列 state, 假设第 0 列全被占据 memset(dp, -1, sizeof(dp)); for(int i = 1; i <= M; i ++) statePre[i] = map[1][i] + 1; dp[1][tri2Ten(statePre)] = 0; //cout << tri2Ten(statePre) << endl; } /* * 搜寻出每一行所有可能的摆放方式 * 限制条件是该行不可以有坏点 * 需要同时得出所有的 state 值 */ void dfs(const int &row, const int &pos, const int &maxNum, const int &s) { dp[row%2][s] = max(dp[row%2][s], maxNum); // 继承 if(pos >= M) return; // 步长不是1, 所以 == 不行 if(pos<M && !stateCur[pos] && !stateCur[pos+1] && !statePre[pos] && !statePre[pos+1]) { // 3*2 的矩形 stateCur[pos] = stateCur[pos+1] = 2; // 对下一层来讲, 只需要 stateCur int k = tri2Ten(stateCur); dfs(row, pos+2, maxNum+1, k); stateCur[pos] = stateCur[pos+1] = 0; // 还原 } if(pos<M-1 && !stateCur[pos] && !stateCur[pos+1] && !stateCur[pos+2]) { stateCur[pos] = stateCur[pos+1] = stateCur[pos+2] = 2; int k = tri2Ten(stateCur); dfs(row, pos+3, maxNum+1, k); stateCur[pos] = stateCur[pos+1] = stateCur[pos+2] = 0; } dfs(row, pos+1, maxNum, s); } int mainFunc() { for(int row = 2; row <= N; row++) { for(int j = 0; j < tri[M+1]; j ++) { // 所有可能状态 j dp[row%2][j] = -1; } for(int j = 0; j < tri[M+1]; j++) { // 上一行的所有可能状态 j if(dp[(row+1)%2][j] == -1) // 无法用来更新, 没有利用价值, 直接跳过 continue; ten2Tri(j); // 获得 statePre for(int l = 1; l <= M; l ++) { if(map[row][l]) stateCur[l] = 2; else stateCur[l] = max(0, statePre[l]-1); } int pass = dp[(row+1)%2][j]; dfs(row, 1, pass, tri2Ten(stateCur)); } } int ans = 0; for(int i = 0; i < tri[M+1]; i ++) ans = max(ans, dp[N%2][i]); return ans; } int main() { freopen("E:\\Copy\\test\\in.txt", "r", stdin); cin >> testCase; while(testCase--) { cin >> N >> M >> K; memset(map, 0, sizeof(map)); for(int i = 1; i <= K; i ++) { int a, b; scanf("%d%d", &a, &b); map[a][b] = 1; } pre_process(); cout << mainFunc() << endl; } return 0; }