这题也算是经典题了,好早之前就看到了,一直没啥想法做,知道是状态压缩,可是没细想过。
A过上道题,就想找个状态压缩的试试哈,就找到这个题啦。
很容易想到,4*4的格子,用一个16位的存下(用int绰绰有余~)就好,这样的话,一个状态就可以用一个数字表示了,标记状态是否用过,用65535的数组就够了。
这个^=好神奇,我开始用了俩位运算表示这个,囧。。。A掉之后觉得时间好慢,看别人的,才看到这个符号。。囧。。
位运算好神奇。。。我开始用的四个方向,先把位置换算成4*4中得坐标,再找上下左右四个方向,慢了几十ms。。。别人用的直接+4 -4 +1 -1(后俩得判断是否越当前行的界),这个很快~
int st_change(int st, int x) { st ^= (1 << x); int a = x/4, b = x % 4; for(int i=0; i<8; i+=2) { int xx = a + dir[i]; int yy = b + dir[i+1]; if( xx >= 0 && xx < 4 && yy >= 0 && yy < 4 ) { int p = ( xx * 4 + yy ); st ^= (1 << p); } } return st; }
int st_change(int st, int x) { st ^= (1 << x); if( x + 4 < 16 ) st ^= (1 << (x + 4)); if( x - 4 >= 0 ) st ^= (1 << (x - 4)); if( x % 4 < 3 && x + 1 < 16 ) st ^= (1 << (x + 1)); if( x % 4 > 0 && x - 1 >= 0 ) st ^= (1 << (x - 1)); return st; }
完整版:
#include <set> #include <map> #include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <string.h> #include <string> #include <algorithm> #include <iostream> #define MID(x,y) ( ( x + y ) >> 1 ) #define L(x) ( x << 1 ) #define R(x) ( x << 1 | 1 ) #define FOR(i,s,t) for(int i=(s); i<(t); i++) #define BUG puts("here!!!") #define STOP system("pause") #define file_r(x) freopen(x, "r", stdin) #define file_w(x) freopen(x, "w", stdout) using namespace std; const int MAX = 70000; bool used[MAX]; typedef pair<int,int> pii; queue<pii> q; int st_change(int st, int x) { st ^= (1 << x); if( x + 4 < 16 ) st ^= (1 << (x + 4)); if( x - 4 >= 0 ) st ^= (1 << (x - 4)); if( x % 4 < 3 && x + 1 < 16 ) st ^= (1 << (x + 1)); if( x % 4 > 0 && x - 1 >= 0 ) st ^= (1 << (x - 1)); return st; } int solve(int st) { while( !q.empty() ) q.pop(); if( st == 0 || st == 65535 ) return 0; q.push(make_pair(st, 0)); while( !q.empty() ) { st = q.front().first; int t = q.front().second; q.pop(); FOR(i, 0, 16) { int now = st_change(st, i); if( now == 0 || now == 65535 ) return t + 1; if( !used[now] ) { used[now] = true; q.push(make_pair(now, t+1)); } } } return -1; } int main() { int ncases, st; char s[10]; scanf("%d", &ncases); while( ncases-- ) { st = 0; memset(used, false, sizeof(used)); FOR(i, 0, 4) { scanf("%s", &s); FOR(k, 0, 4) if( s[k] == 'b' ) st = st | ( 1 << (i * 4 + k) ); } used[st] = true; int ans = solve( st ); if( ans == -1 ) puts("Impossible"); else printf("%d\n", ans); if( ncases ) puts(""); } return 0; }