SRM 422 Level2 CavePassage
前回のSRMの500点問題、手が出なかったので復習。1時間強をかけてダイクストラ法で書いてみました。こんなに時間がかかってしまうと本番ではとても無理だな…。どうやったらこんなのが20、30分で書けるようになるのだろう。
それはさておき、僕が書いたコードはアルゴリズム的には正しい答えを返すみたいですが、システムテストにかけると2秒の時間制限をオーバーするケースが一つあります(57番)。
手元の環境では2.4秒程度で実行されて、TopCoderのサーバーではそれより1割速いくらいなので、あと1割ほどコードを高速化しないといけない。
どこが縮められるだろう。うーん。やっぱりPriorityQueueにaddするのが遅いのかな。
とりあえず貼っとく。
import java.util.ArrayList; import java.util.Arrays; import java.util.PriorityQueue; public class CavePassage { int[] w; int[] t; String[] table; int st; int[] group; public int minimalTime(int[] weights, int[] times, String[] table, int strength) { int N = weights.length; this.w = weights; this.t = times; this.table = table; this.st = strength; this.group = new int[1 << N]; for (int i = 0; i < 1 << N; i++) { ArrayList<Integer> list = new ArrayList<Integer>(); for (int j = 1, c = 0; c < N; j <<= 1, c++) { if ((i & j) > 0) { list.add(c); } } if (list.size() == 0) { continue; } else if (list.size() == 1) { if (w[list.get(0)] <= st) { group[i] = t[list.get(0)]; } } else { if (!trust(list)) { continue; } int sum = 0; for (int n : list) { sum += w[n]; } if (sum > st) { continue; } int max = 0; for (int n : list) { max = Math.max(max, t[n]); } group[i] = max; } } int[] min = new int[1 << (N + 1)]; Arrays.fill(min, Integer.MIN_VALUE); min[0] = 0; PriorityQueue<Item> q = new PriorityQueue<Item>(100000); for (int i = 0; i < (1 << N); i++) { if (group[i] > 0) { q.add(new Item(0, i | (1 << N), group[i])); } } while (min[(1 << N + 1) - 1] < 0) { Item item = q.poll(); if (item == null) { return -1; } if (min[item.end] >= 0) { continue; } min[item.end] = item.time; if ((item.end & 1 << N) > 0) { int st = item.end & ((1 << N) - 1); for (int i = 0; i < st; i++) { if ((i | st) != st) { continue; } int move = i ^ st; if (group[move] > 0 && min[i] < 0) { q .add(new Item(item.end, i, min[item.end] + group[move])); } } } else { for (int i = item.end + 1; i < 1 << w.length; i++) { if ((item.end | i) != i) { continue; } int move = i ^ item.end; int newEnd = i | (1 << N); if (group[move] > 0 && min[newEnd] < 0) { q.add(new Item(item.end, newEnd, min[item.end] + group[move])); } } } } return min[(1 << N + 1) - 1]; } boolean trust(ArrayList<Integer> list) { for (int j = 0; j < list.size(); j++) { boolean found = false; for (int k = 0; k < list.size(); k++) { if (list.get(j) == list.get(k)) { continue; } if (table[list.get(j)].charAt(list.get(k)) == 'Y') { found = true; break; } } if (!found) { return false; } } return true; } class Item implements Comparable<Item> { int start; int end; int time; Item(int s, int e, int t) { this.start = s; this.end = e; this.time = t; } public int compareTo(Item o) { return this.time - o.time; } public String toString() { return "[" + start + "," + end + "," + time + "]"; } } }