自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

遞推算法:令人費解的開關(guān)『拉燈』

開發(fā) 前端 算法
游戲者改變一個燈的狀態(tài)會產(chǎn)生連鎖反應(yīng):和這個燈上下左右相鄰的燈也要相應(yīng)地改變其狀態(tài)。

[[411620]]

題目來源 AcWing[1]。

題目

你玩過“拉燈”游戲嗎?

盞燈排成一個 的方形。

每一個燈都有一個開關(guān),游戲者可以改變它的狀態(tài)。

每一步,游戲者可以改變某一個燈的狀態(tài)。

游戲者改變一個燈的狀態(tài)會產(chǎn)生連鎖反應(yīng):和這個燈上下左右相鄰的燈也要相應(yīng)地改變其狀態(tài)。

我們用數(shù)字 表示一盞開著的燈,用數(shù)字 表示關(guān)著的燈。

下面這種狀態(tài)

  1. 10111 
  2. 01101 
  3. 10111 
  4. 10000 
  5. 11011 

在改變了最左上角的燈的狀態(tài)后將變成:

  1. 01111 
  2. 11101 
  3. 10111 
  4. 10000 
  5. 11011 

再改變它正中間的燈后狀態(tài)將變成:

  1. 01111 
  2. 11001 
  3. 11001 
  4. 10100 
  5. 11011 

給定一些游戲的初始狀態(tài),編寫程序判斷游戲者是否可能在 步以內(nèi)使所有的燈都變亮。

輸入格式

第一行輸入正整數(shù) ,代表數(shù)據(jù)中共有 個待解決的游戲初始狀態(tài)。

以下若干行數(shù)據(jù)分為 組,每組數(shù)據(jù)有 行,每行 個字符。

每組數(shù)據(jù)描述了一個游戲的初始狀態(tài)。

各組數(shù)據(jù)間用一個空行分隔。

輸出格式

一共輸出 行數(shù)據(jù),每行有一個小于等于 的整數(shù),它表示對于輸入數(shù)據(jù)中對應(yīng)的游戲狀態(tài)最少需要幾步才能使所有燈變亮。

對于某一個游戲初始狀態(tài),若 步以內(nèi)無法使所有燈變亮,則輸出 。

數(shù)據(jù)范圍

輸入樣例:

  1. 00111 
  2. 01011 
  3. 10001 
  4. 11010 
  5. 11100 
  6.  
  7. 11101 
  8. 11101 
  9. 11110 
  10. 11111 
  11. 11111 
  12.  
  13. 01111 
  14. 11111 
  15. 11111 
  16. 11111 
  17. 11111 

輸出樣例:

  1. -1 

題解

首先有三點很重要的性質(zhì)需要說明:

  • 如果按哪些燈確定了,那么按這些燈的順序不重要,無論什么順序,結(jié)果都是相同的
  • 我們沒有必要按一盞燈兩次及以上,因為,按兩次,相當(dāng)于沒按,按三次,相當(dāng)于按兩次+一次(也就是一次)

因此:

  • 因為按燈的順序不重要,我們可以先把第一行的燈都按了
  • 我們發(fā)現(xiàn),第一行想按的燈都按過之后,如果想要讓第一行全亮,那么我第二行只能有一種按法,就是按第一行不亮的燈的下面的燈(下面是例子)
  1. 第一行狀態(tài) 10011 (1代表亮的燈) 
  2. 第二行動作 01100 (1代表按按鈕) 

那么,我們怎么保證第二行全亮呢?只能用第三行來解決!

那么,我們怎么保證最后一行(第五行)全亮呢?沒法保證!

我們發(fā)現(xiàn),如果第一行按法確定了,那么接下來二三四五行的按法和能不能全亮就確定了。

因此,對于任意一種輸入狀態(tài),我們把第一行 32 種按法全部遍歷一遍,看看哪些可以全亮(通過檢測第五行狀態(tài)),這些全亮的種有沒有操作次數(shù)小于等于 6 的。有的話,就返回這個操作數(shù),否則就返回 -1 唄。

代碼

  1. #include <iostream> 
  2. #include <cstring> 
  3. #include <algorithm> 
  4. using namespace std; 
  5.  
  6. const int N = 5 + 5;   // 加上 5 更保險 
  7. // 注意接收時用字符串更方便,因為輸入流每行沒有空格 
  8. char g[N][N];  // 記錄燈目前的情況 
  9.  
  10. // 上右下左中 
  11. int dx[5] = {0, 1, 0, -1, 0}; 
  12. int dy[5] = {1, 0, -1, 0, 0}; 
  13.  
  14. // 按第 x 行第 y 列,本身和上下左右五個燈都取反 
  15. void turn(int x, int y) 
  16.     for (int i = 0; i < 5; ++ i) 
  17.     { 
  18.         int a = x + dx[i], b = y + dy[i]; 
  19.         if (0 <= a && a < 5 && 0 <= b && b < 5) 
  20.             g[a][b] = g[a][b] == '1' ? '0''1'
  21.     } 
  22.  
  23. int work() 
  24.     int ans = 2e9; 
  25.     // 第一層循環(huán),把所有第一行按的情況都遍歷 
  26.     // k 是被壓縮了的狀態(tài),最小 0b00000 代表都不按, 
  27.     // 最大 0b11111 代表都按 
  28.      
  29.     // 備份,因為下面的操作會改變 g 
  30.     char backup[N][N]; 
  31.     memcpy(backup, g, sizeof g); 
  32.  
  33.     for (int k = 0; k < (1 << 5); ++ k) 
  34.     { 
  35.         // 確保我們的 g 是輸入的 g 
  36.         memcpy(g, backup, sizeof backup); 
  37.  
  38.         // 當(dāng)?shù)谝恍袨?nbsp;k 時,總操作次數(shù)是.. 
  39.         int res = 0;  // 用 res 來記錄 
  40.  
  41.         // 執(zhí)行 k (根據(jù) k 把第一行按了) 
  42.         for (int j = 0; j < 5; ++ j) 
  43.         { 
  44.             if (k >> j & 1) 
  45.             { 
  46.                 res ++; 
  47.                 turn(0, j); 
  48.             } 
  49.         } 
  50.          
  51.         // 第一行確定了,第二行就確定了 
  52.         // 因為只有合理操作第二行 
  53.         // 才能把第一行全部點亮 
  54.         // 以此類推,第二行定了后,第三行就被第二行決定了 
  55.         for (int i = 0; i < 4; ++ i) 
  56.         { 
  57.             for (int j = 0; j < 5; ++ j) 
  58.             { 
  59.                 if (g[i][j] == '0'
  60.                 { 
  61.                     res ++; 
  62.                     turn(i + 1, j); 
  63.                 } 
  64.             } 
  65.         } 
  66.  
  67.         // 上面的操作一定能保證前 4 行全亮 
  68.         // 但是第 5 行不一定全亮,第 5 行全亮,才是真正有效的操作 
  69.         bool success = true
  70.         for (int j = 0; j < 5; ++ j) 
  71.         { 
  72.             if (g[4][j] == '0'
  73.             { 
  74.                 success = false
  75.                 break; 
  76.             } 
  77.         } 
  78.          
  79.         // 如果是有效的操作,咱看看一共按了幾次開關(guān) 
  80.         if (success) ans = min(res, ans); 
  81.     } 
  82.      
  83.     // 根據(jù)題意返回輸出值 
  84.     if (ans > 6) return -1; 
  85.     return ans; 
  86.  
  87. int main() 
  88.     int n; 
  89.     cin >> n; 
  90.     while (n -- ) 
  91.     { 
  92.         for (int i = 0; i < 5; ++ i) cin >> g[i]; 
  93.         printf("%d\n"work()); 
  94.     } 

參考資料

[1]

 

AcWing: https://www.acwing.com/

 

責(zé)任編輯:武曉燕 來源: Piper蛋窩
相關(guān)推薦

2022-06-10 08:37:45

微軟WindowsWindows 11

2014-11-17 18:23:35

云服務(wù)大數(shù)據(jù)

2010-12-15 17:25:59

Exchange Se

2011-08-02 13:16:36

Objective-C 語法 函數(shù)

2018-09-15 05:09:28

2009-09-11 09:18:17

ASP.NET MVC

2010-03-25 12:21:44

無線網(wǎng)絡(luò)掉線故障

2023-03-13 08:33:36

java邏輯準(zhǔn)確值

2013-02-27 09:16:34

2024-08-08 16:17:29

2017-09-14 09:40:32

PythonUbuntu信號機(jī)制

2023-12-14 07:33:29

Edge瀏覽器微軟

2020-07-29 09:50:54

人工智能網(wǎng)絡(luò)安全技術(shù)

2017-01-19 09:12:39

Apriori算法流程

2018-04-09 11:11:03

RGB臺式機(jī)主機(jī)

2013-03-22 10:30:16

IT主管ITM云計算

2025-04-21 06:53:57

2012-03-23 14:38:31

JavaScript

2024-11-04 09:34:17

2011-06-15 10:20:50

Ubuntu 11.0
點贊
收藏

51CTO技術(shù)棧公眾號