AOJ1110 Patience

問題リンク Patience

  • 概要

Patienceというゲームをする。1〜5が書かれたカードが各4枚あり、それを5*4に並べる。あるカードに注目し、その隣接8マスのカードの中に同じものがあればその2枚を取り除くことができる。取り除けるペアが複数あっても1度に取り除けるのは1ペアだけである。1ペアを取り除いたら空いたマスがでてくるがすぐ次のカードによって詰められる。ゲームの初期状態が与えられるので、何枚までカードの枚数を減らすことができるかを答えよ。

  • 解法

幅優先探索で解きます。
カードの状態は長さ20の'0'〜'5'からなる文字列で表すことができます。'0'は空きマスを表すことにします。ただ、ペアを取り除き、カードを詰めた後の状態を文字列にすることにします。
幅優先探索で到達した最高の深さの状態が答えとなります。

  • ソース
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;

//Patience
public class AOJ1110 {

	void run(){
		int[][] move = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
		Scanner sc = new Scanner(System.in);
		int T = sc.nextInt();
		while(T--!=0){
			String start = "";
			for(int i=0;i<5;i++)for(int j=0;j<4;j++)start+=sc.next();
			List<String> l = new ArrayList<String>();
			l.add(start);
			int step = 20;
			while(!l.isEmpty()){
				List<String> next = new ArrayList<String>();
				Set<String> u = new HashSet<String>();
				for(String s:l){
					char[] ch = s.toCharArray();
					for(int i=0;i<5;i++){
						for(int j=0;j<4;j++){
							char x = ch[i*4+j];
							if(x=='0')break;
							for(int k=0;k<8;k++){
								int ni = i+move[k][0];
								int nj = j+move[k][1];
								if(0<=ni&&ni<5&&0<=nj&&nj<4){
									if(x==ch[ni*4+nj]){
										String n = "";
										for(int a=0;a<5;a++){
											for(int b=0;b<4;b++){
												if(a==i&&b==j||a==ni&&b==nj)continue;
												n += ch[a*4+b];
											}
										}
										n += "00";
										if(!u.contains(n)){
											u.add(n); next.add(n);
										}
									}
								}
							}
						}
					}
				}
				if(next.isEmpty()){
					System.out.println(step);
				}
				step-=2;
				l = next;
			}
		}
	}

	public static void main(String[] args) {
		new AOJ1110().run();
	}
}