AOJ2422 Transparent Mahjong

問題リンク Transparent Mahjong

  • 解法

加える牌を1種類ずつ試していき、上がることができるかをDFSで探索するのが方針です。
配列を2つ用意しました。
c[k]: kと書かれた牌の数
use[k]: kと書かれた牌で探索中に使った枚数(4を超えないようにする)
更に、変数freeが透明な牌の枚数です。
再帰メソッドは
kを3枚使う
(k<=10のとき)k, k+1, k+2のグループをi個作る (0 <= i <= 4)
の組み合わせを全て試しています。
なお、この再帰を呼び出す前にペアになる数字を決め、その数字のuse[x]を2にしているので再帰中は3枚のグループと連続のグループを考えるだけでいいことにしています。
再帰の末端では、
use[k] < c[k]
4 < use[k]
となっていないかをチェックしています。
使用した透明牌の個数はmax{0, use[k]-c[k]}の総和で求まります。

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

//Transparent Mahjong
public class AOJ2422 {

	int[] c, use;
	int free = 0;
	
	boolean f(int k, int u){
		if(free < u)return false;
		if(k==13){
			for(int i=1;i<=12;i++){
				if(use[i]<c[i] || 4<use[i])return false;
			}
			return true;
		}
		if(4<use[k])return false;
		if(use[k]<=1){
			int d = Math.max(0, 3-(c[k]-use[k]));
			use[k]+=3;
			if(f(k, u+d))return true;
			use[k]-=3;
		}
		if(c[k]<=use[k] && f(k+1, u))return true;
		if(k<=10){
			for(int i=1;i<=4;i++){
				int d = 0;
				for(int j=k;j<k+3;j++){
					d += Math.max(0, i-(c[j]-use[j]));
					use[j]+=i;
				}
				if(f(k+1, u+d))return true;
				for(int j=k;j<k+3;j++)use[j]-=i;
			}
		}
		return false;
	}
	
	void run(){
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		c = new int[13];
		use = new int[13];
		for(int i=0;i<3*n+1;i++){
			String s = sc.next();
			if("*".equals(s))free++;
			else c[Integer.parseInt(s)]++;
		}
		List<Integer> res = new ArrayList<Integer>();
		for(int i=1;i<=12;i++){
			if(c[i]<4){
				c[i]++;
				for(int j=1;j<=12;j++){
					Arrays.fill(use, 0);
					use[j] = 2;
					if(f(1, 0)){
						res.add(i);
						break;
					}
				}
				c[i]--;
			}
		}
		if(res.isEmpty())System.out.println(-1);
		else for(int x:res)System.out.println(x);
	}
	
	public static void main(String[] args) {
		new AOJ2422().run();
	}
}