1. 程式人生 > 實用技巧 >LeetCode 354 Russian Doll Envelopes (動態規劃)

LeetCode 354 Russian Doll Envelopes (動態規劃)

題目來源:演算法競賽進階指南

題目標籤:遞迴,二進位制狀態列舉

題目連結:https://www.acwing.com/problem/content/97/

思路:通過二進位制列舉第一行所有可能的更改狀態。固定第一行以後,開始從第一行進行遞迴,如果有0則通過改變下面一個點的狀態來改變當前點的狀態,最後檢查最後一行是否全部是1;

通過二進位制列舉可以枚舉出第一行所有的可能的狀態,如果有答案,答案一定也包含在裡面,因此可以實現不重不漏

程式碼:

#include <iostream>
#include <cstring>

using namespace std;

const
int INF = 100000; char g[10][10]; int dx[5] = {0,-1,0,1,0} , dy[5] = {0,0,1,0,-1}; //根據改變的位置改變相應的值 void turn(int x, int y) { for(int i = 0; i < 5; i ++) { int a = x + dx[i], b = y +dy[i]; // 合法的範圍內進行調整 if(a >= 0 && a < 5 && b >= 0 && b < 5) { g[a][b]
^= 1; } } } int work() { int ans = INF; // 對第一行的 32(1 << 5)次列舉(暴力) 涵蓋了該問題的整個狀態空間 for(int k = 0; k < 1 << 5; k ++) { int res = 0; char backup[10][10]; memcpy(backup, g, sizeof g); //對於第 0 行的調整. for(int j = 0; j < 5; j ++) {
if(k >> j & 1) { res ++; turn(0,j); } } //對於1 - 4的調整. 可以根據下面的turn(i + 1, j)看出 for(int i = 0; i < 4; i ++) { for(int j = 0; j < 5; j ++) { if(g[i][j] == '0') { res ++; turn(i + 1, j); } } } //根據 最後一行進行判斷整個矩陣是否全為1. bool is_successful = true; for(int j = 0; j < 5; j ++) { if(g[4][j] == '0') { is_successful = false; break; } } if(is_successful) ans = min(ans, res); memcpy(g, backup, sizeof g); } //判斷次數 if(ans > 6) return -1; return ans; } int main() { int metric; cin >> metric; while(metric --) { for(int i = 0; i < 5; i ++) cin >> g[i]; //一次性輸入一行 cout << work() <<endl; } return 0; }