SRM 648 Div. 1 Easy: AB (動的計画法)
解法
動的計画法を使う。dp[i][j][p]に「i文字目まででAをj文字使った時にペアpに到達可能かどうか」を記録しておく。
if (!dp[i][j][p]) { dp[i + 1][j + 1][p] = true;// i+1文字目をAにする dp[i + 1][j][p + j] = true;// i+1文字目をBにする }
幅優先探索を用いるとパターンが多すぎて落ちる(誤答コードを後述)。
コード
public class AB { public String createString(int N, int K) { // dp[i][j][p]:= i文字目まででAをj文字使った時のペアpに到達可能かどうか boolean[][][] dp = new boolean[N + 1][N + 1][2001]; dp[0][0][0] = true; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { for (int p = 0; p <= K; p++) { if (!dp[i][j][p]) { continue; } dp[i + 1][j + 1][p] = true;// Aを増やす dp[i + 1][j][p + j] = true;// Bを増やす } } } int A = -1; for (int a = 0; a <= N; a++) { System.out.println(a); if (dp[N][a][K]) { A = a; break; } } if (A == -1) { return ""; } String ans = ""; while (N > 0) { if (A > 0 && dp[N - 1][A - 1][K]) { N--; A--; ans = "A" + ans; } else if (K - A >= 0 && dp[N - 1][A][K - A]) { N--; K -= A; ans = "B" + ans; } } return ans; } class Seq { String seq; int numA, pair; public Seq(String s, int a, int p) { this.seq = s; this.numA = a; this.pair = p; } } }
誤答コード(幅優先探索)
import java.util.ArrayDeque; import java.util.Deque; public class AB { public String createString(int N, int K) { Deque<Seq> deque = new ArrayDeque<>(); deque.addLast(new Seq("A", 1, 0)); deque.addLast(new Seq("B", 0, 0)); while (!deque.isEmpty()) { Seq seq = deque.pollFirst(); if (seq.seq.length() == N) { break; } String aString = seq.seq + "A"; if (aString.length() == N && seq.pair == K) { return aString; } else { deque.add(new Seq(aString, seq.numA + 1, seq.pair)); } String bString = seq.seq + "B"; if (bString.length() == N && seq.pair + seq.numA == K) { return bString; } else { deque.add(new Seq(bString, seq.numA, seq.pair + seq.numA)); } } return ""; } class Seq { String seq; int numA, pair; public Seq(String s, int a, int p) { this.seq = s; this.numA = a; this.pair = p; } } }