AOJ1140 Cleaning Robot

問題リンク Cleaning Robot

  • 解法

巡回セールスマン問題と考えて解くのがたぶん想定解だと思います。けれど、ごり押しでも通せます。
訪れる頂点間の最短距離をBFSで前計算しておき、訪れる順番を全通り試します。O(10!)くらいになるのですが、何とかなります。

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

//Cleaning Robot
public class AOJ1140 {

	static int min;
	static boolean[] used;
	static int[][] dist;
	
	static void dfs(int[] order, int k){
		if(k==order.length){
			int s = 0;
			int from = 0;
			for(int i=0;i<order.length;i++){
				s += dist[from][order[i]];
				from = order[i];
			}
			min = Math.min(min, s);
			return;
		}
		for(int i=1;i<=order.length;i++){
			if(!used[i]){
				used[i] = true;
				order[k] = i;
				dfs(order, k+1);
				used[i] = false;
			}
		}
	}
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int[][] move = {{1,0},{-1,0},{0,1},{0,-1}};
		while(true){
			int w = sc.nextInt();
			int h = sc.nextInt();
			if((w|h)==0)break;
			char[][] m = new char[h][w];
			int id = 1;
			Map<Integer, Integer> ref = new HashMap<Integer, Integer>();
			for(int i=0;i<h;i++){
				char[] s = sc.next().toCharArray();
				for(int j=0;j<w;j++){
					m[i][j] = s[j];
					if(m[i][j]=='*'){
						ref.put(i*w+j, id++);
					}
					if(m[i][j]=='o'){
						ref.put(i*w+j, 0);
					}
				}
			}
			dist = new int[id][id];
			for(int[]a:dist)Arrays.fill(a, Integer.MAX_VALUE);
			for(int i=0;i<h;i++){
				for(int j=0;j<w;j++){
					if(m[i][j]=='o'||m[i][j]=='*'){
						int from = ref.get(i*w+j);
						boolean[][] visited = new boolean[h][w];
						visited[i][j] = true;
						int step = 0;
						List<int[]> list = new ArrayList<int[]>();
						list.add(new int[]{i, j});
						while(!list.isEmpty()){
							List<int[]> next = new ArrayList<int[]>();
							for(int[] a:list){
								if(ref.containsKey(a[0]*w+a[1])){
									dist[from][ref.get(a[0]*w+a[1])] = step;
								}
								for(int k=0;k<4;k++){
									int ni = a[0] + move[k][0];
									int nj = a[1] + move[k][1];
									if(0<=ni&&ni<h&&0<=nj&&nj<w&&m[ni][nj]!='x'&&!visited[ni][nj]){
										visited[ni][nj] = true;
										next.add(new int[]{ni, nj});
									}
								}
							}
							list = next;
							step++;
						}
					}
				}
			}
			boolean f = true;
			for(int i=0;i<id;i++)if(dist[0][i]==Integer.MAX_VALUE)f = false;
			if(!f){
				System.out.println(-1);
				continue;
			}
			min = Integer.MAX_VALUE;
			used = new boolean[id];
			used[0] = true;
			dfs(new int[id-1], 0);
			System.out.println(min);
		}
	}
}