AOJ1260 Organize Your Train

問題リンク Organize Your Train

  • 概要

X本のparking lineとY本のexchange lineがある。parking lineにはそれぞれ文字列で表された列車が停まっている。列車がない状態は"-"となっている。exchange lineは異なるparking lineの端と端を結ぶ。parking lineの初期状態と目標状態が与えられる。目標手数にするための最小ステップ数を答えよ。
1ステップに列車をexchange lineに沿って動かし、列車を連結させることができる。このとき、列車を任意の場所で切ってもよい。切ったら切った側のexchange lineしか使えない。1ステップに移動させられる列車は1つのみである。
目標状態にする方法は必ず1つ以上存在することが保証されている。また、最小ステップ数は1以上6以下であることも保証されている。
X <= 4
列車の全長 <= 10

  • 解法

両側探索で解きます。
初期状態から3ステップまでの状態を列挙、目標状態から3ステップまでの状態を列挙します。
1ステップで得られる状態は高々
(列車を切る箇所)×(どちら側の列車を動かすか)×(どのexchange lineを使うか) = 10*2*7 = 140通り
となります。3ステップならば140^3 ≒ 3*10^6となり、何とかメモリが足ります。
parking lineの状態は","で区切った文字列で表現しました。
abc
-
def
という状態は"abc,-,def,"となります。

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

//Organize Your Train
public class AOJ1260 {

	boolean[][] adj;
	int x, y;
	Map<String, Integer> ref, ref2;

	int trans(char[] s){
		int res = s[0]-'0';
		if(s[1]=='E')res+=x;
		return res;
	}

	String get(String[] s){
		String res = "";
		for(int i=0;i<x;i++)res+=s[i]+",";
		return res;
	}

	void reg(Map<String, Integer> m, String s, List<String> l, int step){
		if(m.containsKey(s))return;
		m.put(s, step);
		l.add(s);
	}
	
	void run(){
		Scanner sc = new Scanner(System.in);
		for(;;){
			x = sc.nextInt(); y = sc.nextInt();
			if((x|y)==0)break;
			adj = new boolean[2*x][2*x];
			while(y--!=0){
				int s = trans(sc.next().toCharArray()), t = trans(sc.next().toCharArray());
				adj[s][t] = adj[t][s] = true;
			}
			String start = "";
			for(int i=0;i<x;i++){
				String s = sc.next();
				start+=s+",";
			}
			String goal = "";
			for(int i=0;i<x;i++){
				String s = sc.next();
				goal+=s+",";
			}
			ref = new HashMap<String, Integer>(); ref2 = new HashMap<String, Integer>();
			List<String> list = new ArrayList<String>();
			ref.put(start, 0);
			list.add(start);
			int step = 1;
			while(!list.isEmpty()&&step<=3){
				List<String> next = new ArrayList<String>();
				for(String v:list){
					String[] s = v.split(",");
					for(int i=0;i<x;i++){
						if("-".equals(s[i]))continue;
						String pre = s[i];
						for(int j=0;j<=s[i].length();j++){
							String former = s[i].substring(0, j);
							String later = s[i].substring(j);
							StringBuffer sb = new StringBuffer(former);
							String frev = sb.reverse().toString();
							sb = new StringBuffer(later);
							String lrev = sb.reverse().toString();
							//move former
							if(former.length()>0){
								for(int k=0;k<2*x;k++){
									if(!adj[i][k])continue;
									s[i] = later.length()>0?later:"-";
									if(k<x){
										String preK = s[k];
										s[k] = "-".equals(s[k])?frev:(frev+s[k]);
										String res = get(s);
										reg(ref, res, next, step);
										s[k] = preK;
									}
									else{
										String preK = s[k-x];
										s[k-x] = "-".equals(s[k-x])?former:(s[k-x]+former);
										String res = get(s);
										reg(ref, res, next, step);
										s[k-x] = preK;
									}
								}
							}
							//move later
							if(later.length()>0){
								for(int k=0;k<2*x;k++){
									if(!adj[i+x][k])continue;
									s[i] = former.length()>0?former:"-";
									if(k<x){
										String preK = s[k];
										s[k] = "-".equals(s[k])?later:(later+s[k]);
										String res = get(s);
										reg(ref, res, next, step);
										s[k] = preK;
									}
									else{
										String preK = s[k-x];
										s[k-x] = "-".equals(s[k-x])?lrev:(s[k-x]+lrev);
										String res = get(s);
										reg(ref, res, next, step);
										s[k-x] = preK;
									}
								}
							}
							s[i] = pre;
						}
					}
				}
				step++;
				list = next;
			}
			step = 1;
			ref2.put(goal, 0);
			list = new ArrayList<String>();
			list.add(goal);
			int min = 6;
			while(!list.isEmpty()&&step<=3){
				List<String> next = new ArrayList<String>();
				for(String v:list){
					if(ref.containsKey(v)){
						min = Math.min(min, ref.get(v)+ref2.get(v));
					}
					String[] s = v.split(",");
					for(int i=0;i<x;i++){
						if("-".equals(s[i]))continue;
						String pre = s[i];
						for(int j=0;j<=s[i].length();j++){
							String former = s[i].substring(0, j);
							String later = s[i].substring(j);
							StringBuffer sb = new StringBuffer(former);
							String frev = sb.reverse().toString();
							sb = new StringBuffer(later);
							String lrev = sb.reverse().toString();
							//move former
							if(former.length()>0){
								for(int k=0;k<2*x;k++){
									if(!adj[i][k])continue;
									s[i] = later.length()>0?later:"-";
									if(k<x){
										String preK = s[k];
										s[k] = "-".equals(s[k])?frev:(frev+s[k]);
										String res = get(s);
										reg(ref2, res, next, step);
										s[k] = preK;
									}
									else{
										String preK = s[k-x];
										s[k-x] = "-".equals(s[k-x])?former:(s[k-x]+former);
										String res = get(s);
										reg(ref2, res, next, step);
										s[k-x] = preK;
									}
								}
							}
							//move later
							if(later.length()>0){
								for(int k=0;k<2*x;k++){
									if(!adj[i+x][k])continue;
									s[i] = former.length()>0?former:"-";
									if(k<x){
										String preK = s[k];
										s[k] = "-".equals(s[k])?later:(later+s[k]);
										String res = get(s);
										reg(ref2, res, next, step);
										s[k] = preK;
									}
									else{
										String preK = s[k-x];
										s[k-x] = "-".equals(s[k-x])?lrev:(s[k-x]+lrev);
										String res = get(s);
										reg(ref2, res, next, step);
										s[k-x] = preK;
									}
								}
							}
							s[i] = pre;
						}
					}
				}
				step++;
				list = next;
			}
			System.out.println(min);
		}
	}

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