AOJ1126 The Secret Number
問題リンク The Secret Number
- 概要
W*Hのボードに、数字もしくはアルファベットが書いてある。あるマスの数字はその下、もしくは右にある数字と繋げて読むことができる。このとき、ボードの中で最も数が大きくなる数字の列を答えよ。
W+H <= 70
- 解法
DPです。マス(i, j)の数字を先頭とする最大の数列は(i+1, j)と(i, j+1)を使って求めることができるので、ボードの右下からDP表を埋めることができます。
dp[i][j] = max(a+dp[i+1][j], a+dp[i][j+1])
ただし、注意があります。ここでいう大きいとは、
文字数が長い方が大きい。文字数が等しかったら、数字として大きい方が大きい。とします。
なぜなら、数字として大きいかだけを見てしまったら、"0001"と"999"の場合"999"が採用されてしまいます。これの何がまずいかというと、あるマスが今の結果を使って整数を作るとき、"?999"よりも"?0001"の方が数値として大きくなるので、"999"を採用してしまうと答えが求まらないのです。(自分はこれで結構はまりました)
数値の比較にBigIntegerを使っていますが、数値の大きい方は文字列として、辞書的に大きい方になるので、StringのcompareTo()でも大丈夫なんじゃないかと思います。
- ソース
import java.math.BigInteger; import java.util.Scanner; //The Secret Number public class AOJ1126 { void run(){ Scanner sc = new Scanner(System.in); for(;;){ int w = sc.nextInt(); int h = sc.nextInt(); if((w|h)==0)break; char[][] m = new char[h][w]; for(int i=0;i<h;i++)m[i]=sc.next().toCharArray(); String[][] dp = new String[h][w]; String res = "0"; for(int i=h-1;i>=0;i--)for(int j=w-1;j>=0;j--){ if(Character.isUpperCase(m[i][j]))continue; String l = m[i][j]+""; String d = m[i][j]+""; if(i+1<h&&!Character.isUpperCase(m[i+1][j]))d+=dp[i+1][j]; if(j+1<w&&!Character.isUpperCase(m[i][j+1]))l+=dp[i][j+1]; if(l.length()!=d.length()){ dp[i][j] = l.length()>d.length()?l:d; } else{ BigInteger bl = new BigInteger(l); BigInteger bd = new BigInteger(d); if(bl.compareTo(bd)>0)dp[i][j] = l; else dp[i][j] = d; } BigInteger b = new BigInteger(dp[i][j]); if(b.compareTo(new BigInteger(res))>0){ res = dp[i][j]; } } System.out.println(new BigInteger(res).toString()); } } public static void main(String[] args) { new AOJ1126().run(); } }