SOL DP Bitmask Bai123

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 66

DP Bitmask

Quy hoạch động bitmask

1
Bài tập

01 QBSELECT

02 VKNIGHTS

03 COWGIRL

2
QBSELECT

Tóm tắt
Cho một ma trận 4 * n, chọn một số ô
sao cho tổng giá trị là lớn nhất, và
không có ô nào được chọn kề nhau

3
QBSELECT

int trau(int i) {
if (i > n) return 0;
// không chọn i, -> qua i + 1
int r1 = trau(i + 1);
//chọn i, bỏ qua i + 1 -> i + 2
int r2 = trau(i + 2) + a[i];
return max(r1, r2);
}
//trau(1)

f[i] = max(f[i - 1], f[i - 2] + a[i]);

4
QBSELECT

int trau(int i, int pre) {


if (i > n) return 0;
if (pre == 1)
// ô i - 1 đã chọn f[i][0] = max(f[i - 1][0], f[i - 1][1]);
// nên không được chọn ô i f[i][1] = f[i - 1][0];
return trau(i + 1, 0);
//ô i - 1 chưa chọn, nên ô i thoải mái
//không chọn i
int r1 = trau(i + 1, 0);
//chọn i
int r2 = trau(i + 1, 1) + a[i];
return max(r1, r2);
}

5
QBSELECT

int trau(int i, int pre) {


if (i > n) return 0;
if (pre == 1) int trau(int i, int pre) {
// ô i - 1 đã chọn if (i > n) return 0;
// nên không được chọn ô i //không chọn i
return trau(i + 1, 0); int res = trau(i + 1, 0);
//ô i - 1 chưa chọn, nên ô i thoải mái //ô i - 1 chưa chọn
//không chọn i if (pre == 0)
int r1 = trau(i + 1, 0); res = max(res, trau(i + 1, 1) + a[i]);
//chọn i return res;
int r2 = trau(i + 1, 1) + a[i]; }
return max(r1, r2);
}

6
QBSELECT

int trau(int i, int pre) {


int trau(int i, int pre) {
if (i > n) return 0;
if (i > n) return 0;
int res = -infinity;
//không chọn i
for (int nxt = 0; nxt <= 1; ++nxt)
int res = trau(i + 1, 0);
if (nxt + pre != 2) {
//ô i - 1 chưa chọn
int cost = 0;
if (pre == 0)
if (nxt == 1) cost = a[i];
res = max(res, trau(i + 1, 1) + a[i]);
res = max(res, trau(i + 1, nxt) + cost);
return res;
}
}
return res;
}

7
QBSELECT
int trau(int i, int pre) {
if (i > n) return 0;
int res = -infinity;
for (int nxt = 0; nxt <= 1; ++nxt)
if (nxt + pre != 2) {
int cost = 0;
if (nxt == 1) cost = a[i];
res = max(res, trau(i + 1, nxt) + cost);
}
return res;
}
int trau(int i, int pre) {
if (i > n) return;
int res = -infinity;
for (int nxt = 0; nxt <= 1; ++nxt)
if (nxt + pre != 2)
res = max(res, trau(i + 1, nxt) + nxt * a[i]);
return res;
}
8
QBSELECT

int trau(int i, int x, int y) {


if (i > n) return 0;
int res = -infinity;
for (int xx = 0; xx <= 1; ++xx)
for (int yy = 0; yy <= 1; ++yy)
if (x + xx != 2 && y + yy != 2 && xx + yy != 2)
res = max(res, trau(i + 1, xx, yy) + xx * a[i][1] + yy * a[i][2]);
return res;
}

9
QBSELECT
int trau(int i, int x, int y, int z) {
if (i > n) return 0;
int res = -infinity;
for (int xx = 0; xx <= 1; ++xx)
for (int yy = 0; yy <= 1; ++yy)
for (int zz = 0; zz <= 1; ++zz)
if (x + xx != 2 && y + yy != 2 && z + zz != 2
&& xx + yy != 2 && yy + zz != 2)
res = max(res,
trau(i + 1, xx, yy, zz)
+ xx * a[i][1]
+ yy * a[i][2]
+ zz * a[i][3]
);
return res;
}

10
QBSELECT

for (int i = 1; i <= n; ++i)


for (int x ...)
for (int y ...)
for (int z ...)
for (int xx ...)
for (int yy ...)
for (int zz ...)

11
QBSELECT

12
QBSELECT

Độ phức tạp?
(Giả sử đã thêm nhớ)
int trau(int i, int x, int y, int z) {
if (i > n) return 0; Số lượng trạng thái: 𝑂(𝑛 ∗ 2 )
int res = -infinity;
for (int xx = 0; xx <= 1; ++xx) Chi phí chuyển: 𝑂(2 )
for (int yy = 0; yy <= 1; ++yy)
for (int zz = 0; zz <= 1; ++zz)
if (x + xx != 2 && y + yy != 2 && z + zz != 2
&& xx + yy != 2 && yy + zz != 2)
res = max(res,
trau(i + 1, xx, yy, zz)
+ xx * a[i][1]
+ yy * a[i][2]
+ zz * a[i][3]
);
return res;
} 13
QBSELECT
int trau(int i, int x, int y, int z) {
if (i > n) return 0;
int res = -infinity;
for (int xx = 0; xx <= 1; ++xx)
for (int yy = 0; yy <= 1; ++yy)
for (int zz = 0; zz <= 1; ++zz)
if (x + xx != 2 && y + yy != 2 && z + zz != 2
&& xx + yy != 2 && yy + zz != 2)
res = max(res,
trau(i + 1, xx, yy, zz)
+ xx * a[i][1]
+ yy * a[i][2]
+ zz * a[i][3]
);
return res;
}

14
QBSELECT
int trau(int i, int x, int y, int z) {
if (i > n) return 0;
int res = -infinity;
for (int mask = 0; mask < 8; ++mask) {
int xx = getBit(mask, 0);
int yy = getBit(mask, 1);
int zz = getBit(mask, 2);
if (x + xx != 2 && y + yy != 2 && z + zz != 2
&& xx + yy != 2 && yy + zz != 2)
res = max(res,
trau(i + 1, xx, yy, zz)
+ xx * a[i][1]
+ yy * a[i][2]
+ zz * a[i][3]
);
}
return res;
}
15
QBSELECT
int trau(int i, int pre_mask) {
if (i > n) return 0;
Độ phức tạp?
int x = getBit(pre_mask, 0);
(Giả sử đã thêm nhớ)
int y = getBit(pre_mask, 1);
int z = getBit(pre_mask, 2);
int res = -infinity; Số lượng trạng thái: 𝑂(𝑛 ∗ 2 )
for (int mask = 0; mask < 8; ++mask) {
int xx = getBit(mask, 0); Chi phí chuyển: 𝑂(2 )
int yy = getBit(mask, 1);
int zz = getBit(mask, 2);
if (x + xx != 2 && y + yy != 2 && z + zz != 2
&& xx + yy != 2 && yy + zz != 2)
res = max(res,
trau(i + 1, mask)
+ xx * a[i][1]
+ yy * a[i][2]
+ zz * a[i][3]
);
}
return res;
16
}
QBSELECT
x + xx != 2 && y + yy != 2 && z + zz != 2

(pre_mask & mask) == 0

17
QBSELECT
int trau(int i, int pre_mask) {
if (i > n) return 0;
int res = -infinity;
for (int mask = 0; mask < 8; ++mask) {
int xx = getBit(mask, 0);
int yy = getBit(mask, 1);
int zz = getBit(mask, 2);
if ((pre_mask & mask) == 0
&& xx + yy != 2 && yy + zz != 2)
res = max(res,
trau(i + 1, mask)
+ xx * a[i][1]
+ yy * a[i][2]
+ zz * a[i][3]
);
}
return res;
}

18
QBSELECT
&& xx + yy != 2 && yy + zz != 2

19
QBSELECT
&& xx + yy != 2 && yy + zz != 2

(mask & (mask << 1)) == 0

20
QBSELECT
int trau(int i, int pre_mask) {
if (i > n) return 0;
Độ phức tạp?
int &res = f[i][pre_mask];
if (res != -1)
return res;
Số lượng trạng thái: 𝑂(𝑛 ∗ 2 )
res = -infinity;
for (int mask = 0; mask < 8; ++mask) {
Chi phí chuyển: 𝑂(2 )
int xx = getBit(mask, 0);
int yy = getBit(mask, 1);
int zz = getBit(mask, 2);
if ((pre_mask & mask) == 0 && (mask & (mask << 1) == 0))
res = max(res,
trau(i + 1, mask)
+ xx * a[i][1]
+ yy * a[i][2]
+ zz * a[i][3]
);
}
return res;
} 21
QBSELECT
for (int i = 1; i <= n; ++i)
for (int mask = 0; mask < 8; ++mask) {
f[i][mask] = -infinity;
for (int pre_mask = 0; pre_mask < 8; ++pre_mask)
if ((pre_mask & mask) == 0 && (mask & (mask << 1) == 0)) {
int xx = getBit(mask, 0);
int yy = getBit(mask, 1);
int zz = getBit(mask, 2);
f[i][mask] = max(f[i][mask],
f[i - 1][pre_mask]
+ xx * a[i][1]
+ yy * a[i][2]
+ zz * a[i][3]
);
}
}
}

22
Q&A

23
VKNIGHS

Tóm tắt
Cho một ma trận 3 * n có một số ô cấm,
tìm số lượng lớn nhất các quân mã có
thể đặt lên bàn cờ, sao cho không có 2
quân mã nào có thể ăn được nhau (sau
1 bước)

24
VKNIGHS

Tóm tắt
Các biến cần quan tâm Cho một ma trận 3 * n có một số ô cấm,
- Các quân mã đã được đặt (tập hợp) tìm số lượng lớn nhất các quân mã có
- Ô đang đứng thể đặt lên bàn cờ, sao cho không có 2
quân mã nào có thể ăn được nhau (sau
1 bước)

25
VKNIGHTS

Làm trâu

Các biến cần quan tâm


- Các quân mã đã được đặt (tập hợp điểm 2D)
- Cột đang đứng

Mỗi lần ta sẽ thêm hẳn 1 cột vào

26
int calc(int i, set<pair<int, int> > placed) {
if (i > n) return 0; //đã điền xong cột cuối cùng
int res = 0;
//duyệt các cách điền cột i
for (int x = 0; x <= 1; ++x) {
if (x == 1 && invalid(placed, {1, i})) continue;
for (int y = 0; y <= 1; ++y) {
if (y == 1 && invalid(placed, {2, i})) continue;
for (int z = 0; z <= 1; ++z) {
if (z == 1 && invalid(placed, {3, i})) continue;
//tạo tập hợp mới
set<pair<int, int> > nxt_placed = placed;
if (x) nxt_placed.insert({1, i});
if (y) nxt_placed.insert({2, i});
if (z) nxt_placed.insert({3, i});
res = max(res, calc(i + 1, nxt_placed) + x + y + z);
}
}
} //calc(1, set rỗng)
return res;
}
27
Invalid
Làm sao xác định có thể thêm một con mã vào tập hợp hay
không?

bool invalid(const set<pair<int, int> > &placed, pair<int, int> pos) {


if (block[pos.first][pos.second])
return true;
//nếu 2 con mã có khoảng cách là 3 thì bọn nó ăn nhau
for (auto knight : placed)
if (abs(knight.first - pos.first) + abs(knight.second - pos.second) == 3)
return true;
return false;
}

28
Thêm nhớ ????
int calc(int i, set<pair<int, int> > placed) {
//...
}

Làm sao xác định một trạng thái đã tính


hay chưa?

map<set<pair<int, int> >, int> f[maxn];

int calc(int i, set<pair<int, int> > placed) {


if (i > n)
return 0; //đã điền xong cột cuối cùng
if (f[i].count(placed) != 0)
return f[i][placed];
int res = 0;
//...
return f[i][placed] = res;
} 29
Thêm nhớ ????
int calc(int i, set<pair<int, int> > placed) { Độ phức tạp?
if (i > n)
return 0; //đã điền xong cột cuối cùng
if (f[i].count(placed) != 0) Số lượng trạng thái:
return f[i][placed]; - i: 𝑂(𝑛)
int res = 0; - placed: 𝑂(2 )
//...
return f[i][placed] = res;
} Chi phí chuyển:
- Duyệt x, y, z: 𝑂 2
- Kiểm tra, thao tác set : 𝑂(𝑛 ∗ 𝑙𝑜𝑔𝑛)
- Hằng số to

Đoán xem làm gì tiếp theo

30
Invalid
bool invalid(const set<pair<int, int> > &placed, pair<int, int> pos) {
if (block[pos.first][pos.second])
return true;
//nếu 2 con mã có khoảng cách là 3 thì bọn nó ăn nhau
for (auto knight : placed)
if (abs(knight.first - pos.first) + abs(knight.second - pos.second) == 3)
return true;
return false;
}

31
int calc(int i, set<pair<int, int> > placed) {
//...
//tạo tập hợp mới
set<pair<int, int> > nxt_placed = placed;
if (x) nxt_placed.insert({1, i});
if (y) nxt_placed.insert({2, i});
if (z) nxt_placed.insert({3, i});
//...
}

32
int calc(int i, set<pair<int, int> > placed) {
//...
//tạo tập hợp mới
set<pair<int, int> > nxt_placed;
for (auto knight : placed)
if (knight.second >= i - 1)
nxt_placed.insert(knight);
if (x) nxt_placed.insert({1, i});
if (y) nxt_placed.insert({2, i});
if (z) nxt_placed.insert({3, i});
//...
}

33
int calc(int i, set<pair<int, int> > placed) {
if (i > n)
return 0; //đã điền xong cột cuối cùng
if (f[i].count(placed) != 0)
return f[i][placed];
int res = 0;
Độ phức tạp?
//duyệt các cách điền cột i
for (int x = 0; x <= 1; ++x) {
if (x == 1 && invalid(placed, {1, i}))
continue;
for (int y = 0; y <= 1; ++y) {
Số lượng trạng thái:
if (y == 1 && invalid(placed, {2, i})) - i:
continue;
for (int z = 0; z <= 1; ++z) {
- placed: ∗

if (z == 1 && invalid(placed, {3, i}))


continue;
//tạo tập hợp mới Chi phí chuyển:
set<pair<int, int> > nxt_placed;
for (auto knight : placed)
- Duyệt x, y, z:
if (knight.second >= i - 1) - Kiểm tra, thao tác set:
nxt_placed.insert(knight); - Hằng số to
if (x) nxt_placed.insert({1, i});
if (y) nxt_placed.insert({2, i});
if (z) nxt_placed.insert({3, i});
res = max(res, calc(i + 1, nxt_placed) + x + y + z);
}
}
}
return f[i][placed]=res;
34
}
int calc(int i, set<pair<int, int> > placed) {
if (i > n)
return 0; //đã điền xong cột cuối cùng
if (f[i].count(placed) != 0)
return f[i][placed];
int res = 0;
//duyệt các cách điền cột i
for (int x = 0; x <= 1; ++x) {
if (x == 1 && invalid(placed, {1, i}))
continue;
for (int y = 0; y <= 1; ++y) {
if (y == 1 && invalid(placed, {2, i}))
continue;
for (int z = 0; z <= 1; ++z) {
if (z == 1 && invalid(placed, {3, i}))
continue;
//tạo tập hợp mới
set<pair<int, int> > nxt_placed;
for (auto knight : placed)
if (knight.second >= i - 1)
nxt_placed.insert(knight);
if (x) nxt_placed.insert({1, i});
if (y) nxt_placed.insert({2, i});
if (z) nxt_placed.insert({3, i});
res = max(res, calc(i + 1, nxt_placed) + x + y + z);
}
}
}
return f[i][placed]=res; 35
}
int calc(int i, set<pair<int, int> > placed) {
//...
//duyệt các cách điền cột i
for (int mask = 0; mask < 8; ++mask) {
int x = getBit(mask, 0);
int y = getBit(mask, 1);
int z = getBit(mask, 2);
if (x == 1 && invalid(placed, {1, i}))
continue;
if (y == 1 && invalid(placed, {2, i}))
continue;
if (z == 1 && invalid(placed, {3, i}))
continue;
//tạo tập hợp mới
set<pair<int, int> > nxt_placed;
for (auto knight : placed)
if (knight.second >= i - 1)
nxt_placed.insert(knight);
if (x) nxt_placed.insert({1, i});
if (y) nxt_placed.insert({2, i});
if (z) nxt_placed.insert({3, i});
res = max(res, calc(i + 1, nxt_placed) + x + y + z);
} 36
}
int calc(int i, set<pair<int, int> > pre_col1, set<pair<int, int> > pre_col2) {
//...
//duyệt các cách điền cột i
for (int mask = 0; mask < 8; ++mask) {
int x = getBit(mask, 0);
int y = getBit(mask, 1);
int z = getBit(mask, 2);
if (x == 1 && invalid(pre_col1, pre_col2, {1, i}))
continue;
if (y == 1 && invalid(pre_col1, pre_col2, {2, i}))
continue;
if (z == 1 && invalid(pre_col1, pre_col2, {3, i}))
continue;
//tạo tập hợp mới
set<pair<int, int> > nxt_placed;
if (x) nxt_placed.insert({1, i});
if (y) nxt_placed.insert({2, i});
if (z) nxt_placed.insert({3, i});
res = max(res, calc(i + 1, pre_col2, nxt_placed) + x + y + z);
}
}

37
int calc(int i, set<int> pre_col1, set<int> pre_col2) {
if (i > n)
return 0; //đã điền xong cột cuối cùng
int res = 0;
//duyệt các cách điền cột i
for (int mask = 0; mask < 8; ++mask) {
int x = getBit(mask, 0);
int y = getBit(mask, 1);
int z = getBit(mask, 2);
if (x == 1 && invalid(pre_col1, pre_col2, 1, i))
continue;
if (y == 1 && invalid(pre_col1, pre_col2, 2, i))
continue;
if (z == 1 && invalid(pre_col1, pre_col2, 3, i))
continue;
//tạo tập hợp mới
set<int> nxt_placed;
if (x) nxt_placed.insert(1);
if (y) nxt_placed.insert(2);
if (z) nxt_placed.insert(3);
res = max(res, calc(i + 1, pre_col2, nxt_placed) + x + y + z);
}
return res; 38
}
Invalid

bool invalid(const set<pair<int, int> > &placed, pair<int, int> pos) {


if (block[pos.first][pos.second])
return true;
//nếu 2 con mã có khoảng cách là 3 thì bọn nó ăn nhau
for (auto knight : placed)
if (abs(knight.first - pos.first) + abs(knight.second - pos.second) == 3)
return true;
return false;
}

39
Invalid

bool invalid(const set<int> &pre_col1, const set<int> &pre_col2, int row, int col) {
if (block[row][col])
return true;
//nếu 2 con mã có khoảng cách là 3 thì bọn nó ăn nhau
for (int knight : pre_col1)
if (abs(knight - row) == 1)
return true;
for (int knight : pre_col2)
if (abs(knight - row) == 2)
return true;
return false;
}

40
int calc(int i, set<int> pre_col1, set<int> pre_col2) {
if (i > n)
return 0; //đã điền xong cột cuối cùng
int res = 0;
//duyệt các cách điền cột i
for (int mask = 0; mask < 8; ++mask) {
int x = getBit(mask, 0);
int y = getBit(mask, 1);
int z = getBit(mask, 2);
if (x == 1 && invalid(pre_col1, pre_col2, 1, i))
continue;
if (y == 1 && invalid(pre_col1, pre_col2, 2, i))
continue;
if (z == 1 && invalid(pre_col1, pre_col2, 3, i))
continue;
//tạo tập hợp mới
set<int> nxt_placed;
if (x) nxt_placed.insert(1);
if (y) nxt_placed.insert(2);
if (z) nxt_placed.insert(3);
res = max(res, calc(i + 1, pre_col2, nxt_placed) + x + y + z);
}
return res; 41
}
int calc(int i, int pre_col1_mask, int pre_col2_mask) {
if (i > n)
return 0; //đã điền xong cột cuối cùng
int res = 0;
//duyệt các cách điền cột i
for (int mask = 0; mask < 8; ++mask) {
int x = getBit(mask, 0);
int y = getBit(mask, 1);
int z = getBit(mask, 2);
if (x == 1 && invalid(pre_col1_mask, pre_col2_mask, 1, i))
continue;
if (y == 1 && invalid(pre_col1_mask, pre_col2_mask, 2, i))
continue;
if (z == 1 && invalid(pre_col1_mask, pre_col2_mask, 3, i))
continue;
res = max(res, calc(i + 1, pre_col2_mask, mask) + x + y + z);
}
return res;
}

42
int calc(int i, int pre_col1_mask, int pre_col2_mask) {
if (i > n)
return 0; //đã điền xong cột cuối cùng Độ phức tạp?
int res = 0;
//duyệt các cách điền cột i Số lượng trạng thái:
for (int mask = 0; mask < 8; ++mask) { - i:
int x = getBit(mask, 0);
- Mask1:
int y = getBit(mask, 1);
int z = getBit(mask, 2);
- Mask2:
if (x == 1 && invalid(pre_col1_mask, pre_col2_mask, 1, i)) Chi phí chuyển:
continue;
- Duyệt mask:
if (y == 1 && invalid(pre_col1_mask, pre_col2_mask, 2, i))
continue; - Kiểm tra:
if (z == 1 && invalid(pre_col1_mask, pre_col2_mask, 3, i)) - Hằng số bé
continue;
res = max(res, calc(i + 1, pre_col2_mask, mask) + x + y + z);
}
return res;
}

43
int calc(int i, int pre_col1_mask, int pre_col2_mask) {
if (i > n)
return 0; //đã điền xong cột cuối cùng
int res = 0;
//duyệt các cách điền cột i
for (int mask = 0; mask < 8; ++mask) {
int x = getBit(mask, 0);
int y = getBit(mask, 1);
int z = getBit(mask, 2);
if (x == 1 && invalid(pre_col1_mask, pre_col2_mask, 1, i))
continue;
if (y == 1 && invalid(pre_col1_mask, pre_col2_mask, 2, i))
continue;
if (z == 1 && invalid(pre_col1_mask, pre_col2_mask, 3, i))
continue;
res = max(res, calc(i + 1, pre_col2_mask, mask) + x + y + z);
}
return res;
}

44
int calc(int i, int pre_col1_mask, int pre_col2_mask) {
if (i > n)
return 0; //đã điền xong cột cuối cùng
int res = 0;
//duyệt các cách điền cột i
for (int mask = 0; mask < 8; ++mask) {
if (invalid(pre_col1_mask, pre_col2_mask, mask, i))
continue;
res = max(res, calc(i + 1, pre_col2_mask, mask) + cntBit(mask));
}
return res;
}

45
Invalid
bool invalid(int pre_col1, int pre_col2, int mask, int col) {
//kiểm tra block
for (int i = 1; i <= 3; ++i)
if (getBit(mask, i - 1) && block[i][col])
return true;

for (int i = 0; i < 3; ++i)


if (getBit(mask, i) && getBit(pre_col1, i + 1))
return true;
for (int i = 0; i < 3; ++i)
if (getBit(mask, i + 1) && getBit(pre_col1, i))
return true;
//----
for (int i = 0; i < 3; ++i)
if (getBit(mask, i) && getBit(pre_col2, i + 2))
return true;
for (int i = 0; i < 3; ++i)
if (getBit(mask, i + 2) && getBit(pre_col2, i))
return true;
return false;
46
}
Invalid
bool invalid(int pre_col1, int pre_col2, int mask, int col) {
//kiểm tra block
for (int i = 1; i <= 3; ++i)
if (getBit(mask, i - 1) && block[i][col])
return true;

if (mask & (pre_col1 << 1))


return true;
if ((mask << 1) & pre_col1)
return true;
//----
if (mask & (pre_col2 << 2))
return true;
if ((mask << 2) & pre_col2)
return true;

return false;
}
47
Độ phức tạp?
int calc(int i, int pre_col1_mask, int pre_col2_mask) {
if (i > n) Số lượng trạng thái:
return 0; //đã điền xong cột cuối cùng - i:
int &res = f[i][pre_col1_mask][pre_col2_mask]; - Mask1:
if (res != -1) return res; - Mask2:
res = 0;
//duyệt các cách điền cột i Chi phí chuyển:
for (int mask = 0; mask < 8; ++mask) { - Duyệt mask:
if (invalid(pre_col1_mask, pre_col2_mask, mask, i)) - Kiểm tra:
continue; - Hằng số bé
res = max(res, calc(i + 1, pre_col2_mask, mask) + cntBit(mask));
}
return res;
}

48
Q&A

49
COWGIRL

Tóm tắt
Cho một ma trận n*m, đếm số cách
điền 0 1 vào bảng sao cho không có
bảng con 2*2 nào có toàn số 1 hoặc
toàn số 0
- n * m <= 30
Min(n, m) <= 5

50
COWGIRL

Làm trâu

Các biến cần quan tâm


- Cột đang đứng
- Bảng hiện tại

Mỗi lần ta sẽ thêm hẳn 1 cột vào


Chỉ cần lưu cột cuối cùng

51
int calc(int i, int pre_mask) {
if (i > nCol)
return 1;
int res = 0;
for (int mask = 0; mask < (1 << nRow); ++mask)
if (i != 1 && invalid(mask, pre_mask))
continue;
else
res += calc(i + 1, mask);
return res;
}

//calc(1, 0)

52
Invalid
Làm sao xác định có hình vuông 2 * 2 nào không thỏa mãn
hay không?

bool invalid(int mask, int pre) {


for (int i = 0; i < nRow - 1; ++i) {
int a = getBit(mask, i);
int b = getBit(mask, i + 1);
int c = getBit(pre, i);
int d = getBit(pre, i + 1);
if (a + b + c + d == 0 || a + b + c + d == 4)
return true;
}
return false;
}

53
int calc(int i, int pre_mask) {
if (i > nCol)
return 1;
int res = 0;
for (int mask = 0; mask < (1 << nRow); ++mask)
if (i != 1 && invalid(mask, pre_mask))
continue;
else
res += calc(i + 1, mask);
return res;
}

54
Độ phức tạp?
int calc(int i, int pre_mask) {
if (i > nCol)
return 1; Số lượng trạng thái:
int &res = f[i][pre_mask]; - i:
if (res != -1) return res; - Pre_mask:
res = 0;
for (int mask = 0; mask < (1 << nRow); ++mask)
if (i != 1 && invalid(mask, pre_mask)) Chi phí chuyển:
continue; - Duyệt mask:
else
- Kiểm tra, thao tác set:
res += calc(i + 1, mask);
return res;
}
Đoán xem làm gì tiếp theo

55
Invalid

bool invalid(int mask, int pre) {


for (int i = 0; i < nRow - 1; ++i) {
int a = getBit(mask, i);
int b = getBit(mask, i + 1);
int c = getBit(pre, i);
int d = getBit(pre, i + 1);
if (a + b + c + d == 0 || a + b + c + d == 4)
return true;
}
return false;
}

56
Invalid

57
Invalid

bool invalid(int mask, int pre) {


//Kiểm tra hình vuông 4 số 1
int x = (mask & pre);
if (x & (x << 1)) return true;

//...
}

58
Invalid

bool invalid(int mask, int pre) {


//...
//Kiểm tra hình vuông 4 số 0
//???
}

59
Invalid

bool invalid(int mask, int pre) {


//Kiểm tra hình vuông 4 số 1
int x = (mask & pre);
if (x & (x << 1)) return true;

//Kiểm tra hình vuông 4 số 0


int y = (~mask & ~pre) & ((1 << nRow) - 1);
if (y & (y << 1)) return true;
return false;
}

60
Q&A

61
Lưu ý

Bitmask KHÔNG làm thay đổi dpt (chính) thuật toán.

Bitmask KHÔNG làm thay đổi bản chất của hàm qhđ

Bitmask giúp thuận tiện hơn trong việc lưu bảng


trạng thái

62
Multi-test với đệ
quy có nhớ

63
Multi-test với đệ quy có nhớ

int t; int calc(int i, int pre_mask) {


cin >> t; //...
for (int i = 1; i <= t; ++i) { int &res = f[i][pre_mask];
//... if (res != -1) return res;
memset(f, 255, sizeof(f)); //...
//hoặc for để gán lại mảng f = -1 }
cout << calc(1, 0) << '\n';
}

64
Multi-test với đệ quy có nhớ

int f[maxn][1 << 5];


bool memo[maxn][1 << 5];
//... int calc(int i, int pre_mask) {
int t; //...
cin >> t; int &res = f[i][pre_mask];
for (int i = 1; i <= t; ++i) { if (memo[i][pre_mask] == true) return res;
//... memo[i][pre_mask] = true;
memset(memo, false, sizeof(memo)); //...
//hoặc for để gán lại mảng memo = false }
cout << calc(1, 0) << '\n';
}

65
Multi-test với đệ quy có nhớ

int f[maxn][1 << 5];


int memo[maxn][1 << 5], time_DP;
int calc(int i, int pre_mask) {
//...
//...
int t;
int &res = f[i][pre_mask];
cin >> t;
if (memo[i][pre_mask] == time_DP) return res;
for (int i = 1; i <= t; ++i) {
memo[i][pre_mask] = time_DP;
//...
//...
time_DP = i;
}
cout << calc(1, 0) << '\n';
}

66

You might also like