AOJ0503 Cup

問題リンク Cup

  • 解法

Mが結構大きい数字ですがコップの動きをシミュレートするだけで解けます。
あるコップの状態において動かし方は高々2通りしかありません。更にそのうちの1通りは1手前の状態に戻すための動かし方なので、結局動かし方は1通りに定まります。初手だけは動かし方が2通りあるかもしれないのでどちらも試します。
トレイの状態は1つの整数で表しました。コップKがあったら2^Kが1になっているような整数です。

  • ソース
import java.util.Scanner;

//Cup
public class AOJ0503 {

	int[] last;
	int N, M;
	
	int f(int[] c, int from, int to){
		int res = 1;
		boolean con = true;
		while(!(c[0]==(1<<N)-1||c[2]==(1<<N)-1)&&res<=M){
			con = true;
			for(int f=0;f<3&&con;f++)for(int t=0;t<3&&con;t++){
				if(Math.abs(f-t)>1)continue;
				if(from==t&&to==f)continue;
				if(last[c[f]]<=last[c[t]])continue;
				c[t]+=1<<last[c[f]]; c[f]-=1<<last[c[f]];
				from = f; to = t;
				con = false;
			}
			res++;
		}
		return res;
	}
	
	void run(){
		last = new int[1<<15];
		for(int S=0;S<1<<15;S++){
			int k = 14;
			while(k>=0&&((S>>k)&1)==0)k--;
			last[S] = k;
		}
		Scanner sc = new Scanner(System.in);
		for(;;){
			N = sc.nextInt(); M = sc.nextInt();
			if((N|M)==0)break;
			int[] cup = new int[3];
			for(int i=0;i<3;i++){
				int k = sc.nextInt();
				while(k--!=0)cup[i]+=1<<(sc.nextInt()-1);
			}
			if(cup[0]==(1<<N)-1||cup[2]==(1<<N)-1){
				System.out.println(0); continue;
			}
			int res = M+1;
			for(int f=0;f<3;f++)for(int t=0;t<3;t++){
				if(Math.abs(f-t)>1)continue;
				if(last[cup[f]]<=last[cup[t]])continue;
				int[] c = new int[3];
				c[0] = cup[0]; c[1] = cup[1]; c[2] = cup[2];
				c[t]+=1<<last[c[f]]; c[f]-=1<<last[c[f]];
				res = Math.min(res, f(c, f, t));
			}
			System.out.println(M<res?"-1":res);
		}
	}
	
	public static void main(String[] args) {
		new AOJ0503().run();
	}
}