CodeForces - 111C(狀壓dp)
阿新 • • 發佈:2020-10-05
int n, m; int dp[21][1 << 7][1 << 7];//dp[row][now][pre] int num[1 << 7];//存該狀態有幾個1 inline int lowbit(int x) { return (x & (-x)); } //注意n * m < 40 //所以min(n, m) <= 6,swap即可 int main() { scanf("%d %d", &n, &m); if (n < m) swap(n, m); if (m == 1) { printf("%d\n", n / 3 * 2 + (n % 3 == 2 ? 1 : 0)); return 0; } //if (m == 2) { // printf("%d\n", n / 3 * 4 + n % 3); // return 0; //} //if (n == 3 || m == 3) { //} //保證m 小於 7 int limit = 1 << m; for (int i = 1; i < limit; ++i) num[i] = num[i - lowbit(i)] + 1; for (int i = 0; i < limit; ++i) { dp[0][i][limit - 1] = m - num[i];//1表示當前位置有蜘蛛 } for (int now = 0; now < limit; ++now) { for (int pre = 0; pre < limit; ++pre) { int temp = pre << 1;//不能超出limit-1 if (temp >= limit) temp -= limit; if ((pre | temp | (pre >> 1) | now) != limit - 1) continue; dp[1][now][pre] = max(dp[1][now][pre], dp[0][pre][limit - 1] + m - num[now]); } } for (int i = 2; i < n; ++i) {//當前行 for (int now = 0; now < limit; ++now) {//當前的狀態 for (int pre = 0; pre < limit; ++pre) {//上一次的狀態 //if ((pre | (now << 1) | (now >> 1) | now) != limit - 1) continue; for (int prep = 0; prep < limit; ++prep) { int temp = pre << 1;//不能超出limit-1 if (temp >= limit) temp -= limit; if ((pre | temp | (pre >> 1) | now | prep) != limit - 1) continue; dp[i][now][pre] = max(dp[i][now][pre], dp[i - 1][pre][prep] + m - num[now]); } } } } int ans = 0; for (int now = 0; now < limit; ++now) { for (int pre = 0; pre < limit; ++pre) { int temp = now << 1; if (temp >= limit) temp -= limit; if ((pre | temp | (now >> 1) | now) != limit - 1) continue; ans = max(ans, dp[n - 1][now][pre]); //printf("dp[%d][%d][%d] = %d%c", n - 1, now, pre, dp[n - 1][now][pre], pre == limit - 1 ? '\n' : ' '); } } printf("%d\n", ans); return 0; }