AOJ - Problem 1110 : Patience

全探索で解ける問題です。幅優先探索でも深さ優先探索でも解けると思いますが、今回は深さ優先探索で解きました。同じ状態を再び探索しないようにメモしながら探索しました。2枚のカードを取り出したときカードを移動させる処理が少し煩わしいと感じました。

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;


int dx[8] = {-1,0,1,-1,1,-1,0,1};
int dy[8] = {-1,-1,-1,0,0,1,1,1};
int ans;

int card_count(vector<string> c){
	int cnt=0;
	for(int y=0 ; y < 5 ; y++ ){
		for(int x=0 ; x < 4 ; x++ ){
			if( c[y][x] != '*' )
				cnt++;
		}
	}
	return cnt;
}

void shift(vector<string>& c){
	string s;
	for(int y=0 ; y < 5 ; y++ ){
		for(int x=0 ; x < 4 ; x++ ){
			if( c[y][x] != '*' ){
				s.push_back( c[y][x] );
			}
		}
	}
	for(int y=0 ; y < 5 ; y++ ){
		for(int x=0 ; x < 4 ; x++ ){
			if( y*4 + x < s.size() ){
				c[y][x] = s[y*4+x];
			}else{
				c[y][x] = '*';
			}
		}
	}
}

void solve(vector<string> c, map< vector<string> , bool >& m){
	if( m[c] == true ) return;
	m[c] = true;

	for(int y=0 ; y < 5 ; y++ ){
		for(int x=0 ; x < 4 ; x++ ){
			if( c[y][x] == '*' ) continue;

			char ch = c[y][x];
			for(int i=0 ; i < 8 ; i++ ){
				int mx = x + dx[i];
				int my = y + dy[i];
				if( mx < 0 || my < 0 || mx >= 4 || my >= 5 ) continue;
				
				if( ch == c[my][mx] ){
					vector<string> c2 = c;
					c2[y][x] = '*';
					c2[my][mx] = '*';
					shift( c2 );
					int cnt = card_count( c2 );
					ans = min( ans , cnt );
					solve( c2 , m );
				}
			}
		}
	}
}

int main(){
	int n;
	cin >> n;
	for(int i=0 ; i < n ; i++ ){
		vector<string> c;
		map< vector<string> , bool > m;
		for(int y=0 ; y < 5 ; y++ ){
			string s;
			for(int x=0 ; x < 4 ; x++ ){
				char ch;
				cin >> ch;
				s.push_back( ch );
			}
			c.push_back( s );
		}
		ans = 20;
		solve( c , m );
		cout << ans << endl;
	}
}