1. 程式人生 > >洛谷1764 翻轉遊戲 - 枚舉 + 搜索

洛谷1764 翻轉遊戲 - 枚舉 + 搜索

view radius 現在 輸入 pen 次數 ring 上下左右 ssi

題目描述

kkke在一個n*n的棋盤上進行一個翻轉遊戲。棋盤的每個格子上都放有一個棋子,每個棋子有2個面,一面是黑色的,另一面是白色的。初始的時候,棋盤上的棋子有的黑色向上,有的白色向上。現在kkke想通過最少次數的翻轉,使得棋盤上所有的棋子都是同一個顏色向上的(即全是黑色向上的,或全是白色向上的)。每次翻轉的時候,kkke可以選擇任意一個棋子,將它翻轉,同時,與它上下左右分別相鄰的4個棋子也必須同時翻轉。

輸入輸出格式

輸入格式:

輸入的第一行是一個整數n,表示棋盤是n*n的,

接下來有n行,每行包括n個字母,表示初始的棋盤狀態。如果字母是w,則表示這個棋子當前是白色向上的,如果字母是b,則表示這個棋子當前是黑色向上的。

輸出格式:

輸出為一行,如果無法翻轉出目標狀態,則輸出“Impossible”,否則輸出一個整數,表示kkke最少需要翻轉的次數。

輸入輸出樣例

輸入樣例#1:
4
bwwb
bbwb
bwwb
bwww
輸出樣例#1:
4

說明

【數據範圍】

對於30%的數據,1<=n<=4

對於100%的數據,1<=n<=16

題解

  看到這一題, 我試了試 IDA*, 看看能水幾分, 沒想到只能水30, 果斷滾粗。

  直接爆搜顯然是會TLE 的, 那麽只能考慮其他辦法。

  那麽我們枚舉第一行的翻轉, 並把翻轉後的圖記錄, 進行第二行的搜索。

  由於第一行已經不能再翻, 如果第一行存在沒有達到目標 顏色的棋子,只能由第二行來翻轉。

  所以可以根據第一行的翻轉情況 來 給第二行進行翻轉, 並且可能性僅一種。

  這樣一直翻轉到最後一行結束, 那麽除了最後一行 其他棋子 一定達到了目標顏色。

  最後再判斷最後一行棋子是否都達到了目標顏色, 如果達到了就更新答案。

代碼

原諒我醜的不行的代碼

技術分享圖片
 1 #include<cstring>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #define rep(i,a,b) for( int i = (a); i <= (b); ++i )
 5
#define per(i,a,b) for( int i = (a); i >= (b); --i ) 6 using namespace std; 7 8 const int N = 20, inf = ~0U >> 1; 9 10 int n, mp[N][N], ans, tmp[N][N]; 11 char s[N]; 12 13 int cal( int x , int pos ) { 14 return (x >> pos) & 1; 15 } 16 17 int work( int re , int col) { 18 rep( i, 1, n - 1 ) rep( j, 0, n - 1 ) if( tmp[i - 1][j] != col ){ 19 re++; 20 tmp[i][j] ^= 1; 21 tmp[i + 1][j] ^= 1; 22 if(j) tmp[i][j - 1] ^= 1; 23 if(j != n - 1) tmp[i][j + 1] ^= 1; 24 } 25 rep( j, 0, n - 1 ) if( tmp[n - 1][j] != col ) return inf; 26 return re; 27 } 28 29 int dfs() { 30 int re = inf; 31 rep( i, 0, (1 << n) - 1 ) rep( col, 0, 1){ 32 rep( j, 0, n - 1 ) rep( k, 0, n - 1 ) tmp[j][k] = mp[j][k]; 33 int cnt = 0; 34 rep( j, 0, n - 1 ) if( cal( i, j ) ) cnt++; 35 rep( j, 0, n - 1 ) if( cal( i, j ) ^ cal( i , j - 1 ) ^ cal( i, j + 1 ) ) tmp[0][j] ^= 1; 36 rep( j, 0, n - 1 ) if( cal( i, j ) ) tmp[1][j] ^= 1; 37 re = min( re, work(cnt, col) ); 38 } 39 return re; 40 } 41 42 int main() 43 { 44 scanf("%d",&n); 45 rep( i, 0, n - 1 ) { 46 scanf("%s",s); 47 rep( j, 0, n - 1 ) mp[i][j] = s[j] == w; 48 } 49 ans = dfs(); 50 if( ans == inf ) printf("Impossible\n"); 51 else printf("%d\n", ans); 52 }
View Code

洛谷1764 翻轉遊戲 - 枚舉 + 搜索