Codeforces 903F Clear The Matrix(状态压缩DP)
題目鏈接?Clear The Matrix
題意 給定一個$4 * n$的矩形,里面的元素為$'.'$或$'*'$。現在有$4$種正方形可以覆蓋掉$'*'$,正方形的邊長分別為$1,2,3,4$。
?求把整個矩形變成全$'.'$的最小代價。
?
?
考慮狀壓DP
設$f[i][j]$為前$i$列已經全部變成'.',第$i + 1$到第$i + 4$列的這$16$個格子狀態為$j$的最小花費。
這$16$個格子標號如下
$0$? ?$4$? ?$8$? ?$12$
$1$? ?$5$? ?$9$? ?$13$
$2$? ?$6$? $10$? $14$
$3$? ?$7$? $11$? $15$
我們可以枚舉$0,1,2,3$這$4$個格子。以當前格子為左上角的正方形的邊長。
其中$0$號格子可以放邊長為$0, 1, 2, 3, 4$的正方形;
$1$號格子可以放邊長為$0, 1, 2, 3$的正方形;
$2$號格子可以放邊長為$0, 1, 2$的正方形;
$3$號格子可以放邊長為$0, 1$的正方形;
放邊長為$0$的正方形等效為不放。
當枚舉的這些正方形可以完全蓋住$0,1,2,3$這$4$個格子的時候,就可以進行狀態轉移。
狀態稍微有點復雜,用二進制位表示……
?
時間復雜度$O(n * 2^{16} * 5!)$
?
#include <bits/stdc++.h>using namespace std;#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)const int N = 1e3 + 10;
const int S = 1 << 16;char s[N];
int f[N][S + 2];
int a[6][N];
int c[10];
int g[10];
int n;
int pre[N];
int ans;
int cnt, mask;void up(int &a, int b){ if (a > b) a = b;}
inline get(int x){ return x ^ (S - 1);}int main(){scanf("%d", &n);rep(i, 1, 4) scanf("%d", c + i);rep(i, 1, 4){scanf("%s", s + 1);rep(j, 1, n) a[i][j] = s[j] == '*';}rep(k, 0, n){rep(i, 0, S + 1) f[k][i] = 1e9;}cnt = -1;mask = 0;rep(i, 1, 4){rep(j, 1, 4){++cnt;if (a[j][i]) mask |= (1 << cnt);}}f[0][mask] = 0;g[0] = 0;g[1] = 1;g[2] = (1 << 0) ^ (1 << 1) ^ (1 << 4) ^ (1 << 5);g[3] = (1 << 0) ^ (1 << 1) ^ (1 << 2);g[3] ^= ((1 << 4) ^ (1 << 5) ^ (1 << 6));g[3] ^= ((1 << 8) ^ (1 << 9) ^ (1 << 10));g[4] = (1 << 16) - 1;rep(k, 0, n){int extra = 0;rep(j, 1, 4) if (a[j][k + 5]) extra |= (1 << (j + 11));rep(j, 0, S - 1){if (f[k][j] >= 1e9) continue;rep(aa, 0, 4){rep(bb, 0, 3){rep(cc, 0, 2){rep(dd, 0, 1){int cnt = get(g[aa]) & get(g[bb] << 1) & get(g[cc] << 2) & get(g[dd] << 3);if ((cnt & j & 15) == 0){int nowmask = cnt & j;nowmask >>= 4;nowmask ^= extra;up(f[k + 1][nowmask], f[k][j] + c[aa] + c[bb] + c[cc] + c[dd]); }}}}}}}ans = 1e9;rep(i, n - 4, n) ans = min(ans, f[i][0]);printf("%d\n", ans);return 0;
}
我們可以考慮使用滾動數組,于是空間大大節省
?
#include <bits/stdc++.h>using namespace std;#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define MP make_pair
#define fi first
#define se secondtypedef long long LL;const int N = 1e3 + 10;
const int S = 1 << 16;char s[N];
int f[2][S + 2];
int a[6][N];
int c[10];
int g[10];
int n;
int pre;
int ans;
int cnt, mask;void up(int &a, int b){ if (a > b) a = b;}
inline get(int x){ return x ^ (S - 1);}int main(){scanf("%d", &n);rep(i, 1, 4) scanf("%d", c + i);rep(i, 1, 4){scanf("%s", s + 1);rep(j, 1, n) a[i][j] = s[j] == '*';}rep(k, 0, 1) rep(i, 0, S + 1) f[k][i] = 1e9;cnt = -1;mask = 0;rep(i, 1, 4){rep(j, 1, 4){++cnt;if (a[j][i]) mask |= (1 << cnt);}}f[0][mask] = 0;pre = 0;g[0] = 0;g[1] = 1;g[2] = (1 << 0) ^ (1 << 1) ^ (1 << 4) ^ (1 << 5);g[3] = (1 << 0) ^ (1 << 1) ^ (1 << 2);g[3] ^= ((1 << 4) ^ (1 << 5) ^ (1 << 6));g[3] ^= ((1 << 8) ^ (1 << 9) ^ (1 << 10));g[4] = (1 << 16) - 1;rep(i, 0, n){int extra = 0;rep(j, 1, 4) if (a[j][i + 5]) extra |= (1 << (j + 11));rep(j, 0, S + 1) f[pre ^ 1][j] = 1e9;rep(j, 0, S - 1){if (f[pre][j] >= 1e9) continue;rep(aa, 0, 4){rep(bb, 0, 3){rep(cc, 0, 2){rep(dd, 0, 1){int cnt = get(g[aa]) & get(g[bb] << 1) & get(g[cc] << 2) & get(g[dd] << 3);if ((cnt & j & 15) == 0){int nowmask = cnt & j;nowmask >>= 4;nowmask ^= extra;up(f[pre ^ 1][nowmask], f[pre][j] + c[aa] + c[bb] + c[cc] + c[dd]); }}}}}}pre ^= 1;}printf("%d\n", f[pre][0]);return 0;
}
?
?
不過這個做法還不是最優的= =
官方題解給出的做法是只存后面12個格子的狀態的
因為當考慮某一列的時候一旦用到$4*4$的正方形,其他邊長的正方形就不用再考慮了……直接無視掉。
這樣的話可以直接從$f[k][nowmask]$轉移到$f[k + 1][0]$
時間復雜度$O(n * 2^{12} * 96)$
?
#include <bits/stdc++.h>using namespace std;#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)const int N = 1e3 + 10;
const int S = 1 << 12;char s[N];
int f[2][S + 2], a[6][N], c[10], g[10];
int n, x, cnt, mask, ans;void up(int &a, int b){ if (a > b) a = b;}
inline get(int x){ return x ^ (S - 1);}int main(){scanf("%d", &n);rep(i, 1, 4) scanf("%d", c + i);rep(i, 1, 4){scanf("%s", s + 1);rep(j, 1, n) a[i][j] = s[j] == '*';}rep(k, 0, 1) rep(i, 0, S + 1) f[k][i] = 1e9;cnt = -1;mask = 0;rep(i, 1, 3){ rep(j, 1, 4){ ++cnt; if (a[j][i]) mask |= (1 << cnt); }}f[0][mask] = 0;x = 0;g[0] = 0;g[1] = 1;g[2] = 51;g[3] = 1911;rep(i, 0, n){int extra = 0;rep(j, 1, 4) if (a[j][i + 4]) extra |= (1 << (j + 7));rep(j, 0, S + 1) f[x ^ 1][j] = 1e9;rep(j, 0, S - 1){if (f[x][j] >= 1e9) continue;rep(aa, 0, 3){rep(bb, 0, 3){rep(cc, 0, 2){rep(dd, 0, 1){int cnt = get(g[aa]) & get(g[bb] << 1) & get(g[cc] << 2) & get(g[dd] << 3);if ((cnt & j & 15) == 0){mask = (cnt & j) >> 4;mask ^= extra;up(f[x ^ 1][mask], f[x][j] + c[aa] + c[bb] + c[cc] + c[dd]); }}}}}up(f[x ^ 1][0], f[x][j] + c[4]);}x ^= 1;}printf("%d\n", f[x][0]);return 0;
}
?
轉載于:https://www.cnblogs.com/cxhscst2/p/8253566.html
總結
以上是生活随笔為你收集整理的Codeforces 903F Clear The Matrix(状态压缩DP)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 金发晶的价位是多少钱一克
- 下一篇: Vue(十)生命周期