AtCoder Beginner Contest 027 D - ロボット
問題
https://beta.atcoder.jp/contests/abc027/tasks/abc027_d
数直線の原点にロボットが置かれている。 はじめ、ロボットの幸福度は 0 である。 このロボットに命令列が与えられる。 命令列は次の 3 文字のみからなり、先頭から末尾まで順に実行される。
M : 正または負の好きな向きに、距離 1 だけ移動する。 + : 今の座標を x とすると、幸福度が +x だけ変化する。 - : 今の座標を x とすると、幸福度が −x だけ変化する。
命令列を実行し終えた後、 ロボットは原点に戻っていなければならない 。 命令列を実行している間、ロボットの座標および幸福度は負になり得る。 最終的な幸福度を最大化するようにロボットが移動したとき、最終的な幸福度を求めよ。
方針
部分点解法であるDPで解くこととします。計算量は
回目の命令で の位置にいる時の最大値とします。( 回目の命令= 文字目の文字とします。)
のときに、への更新パターンは以下のように考えられます。
- 命令 が の場合
回目に位置 にいるためには、 回目に位置 または にいる必要があります。
または の大きい方
- 命令 が の場合
回目に位置 にいるとき、 回目は 分だけ値が増えます。
- 命令 が の場合
回目に位置 にいるとき、 回目は 分だけ値が減ります。
以上の場合をまとめればいいのですが、地点 に関しては負の値も取りうるので、
基準点を 分だけずらしておきます。
また、値の開始位置は になるため、の値は 、他は に初期化しておきます。
最終的に一番最初にいた位置(地点 )にいる必要があるので、求めるべき解は です。
実装
import java.util.Arrays; import java.util.Scanner; public class Main { static int INF = 1 << 30; public static void main(String[] args) { Scanner in = new Scanner(System.in); char[] s = in.next().toCharArray(); int n = s.length; int offset = n; int[][] dp = new int[n+1][n+1+offset]; for (int i = 0; i <= n; i++) { Arrays.fill(dp[i], -INF); } dp[0][offset] = 0; for (int i = 0; i < n; i++) { for (int j = 1; j < n+offset; j++) { if (s[i] == 'M') { dp[i+1][j] = Math.max(dp[i][j+1], dp[i][j-1]); } else if (s[i] == '+') { dp[i+1][j] = dp[i][j] + (j-offset); } else if (s[i] == '-') { dp[i+1][j] = dp[i][j] - (j-offset); } } } System.out.println(dp[n][offset]); } }