Created
February 1, 2015 00:13
-
-
Save mikecat/2e599527e675cfc97c14 to your computer and use it in GitHub Desktop.
CodeIQ「中学入試から:概数と計算」解答コード
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// GaisuToKesan.java | |
import java.util.Scanner; | |
import java.math.BigDecimal; | |
import java.math.MathContext; | |
class GaisuToKesan { | |
// 答えを格納するリストのクラス | |
private static class AnswerList { | |
private String answer; | |
private AnswerList nextAnswer; | |
public AnswerList() { | |
this(null); | |
} | |
public AnswerList(String answer) { | |
this.answer = answer; | |
this.nextAnswer = null; | |
} | |
public void setNextAnswer(AnswerList nextAnswer) { | |
this.nextAnswer = nextAnswer; | |
} | |
public AnswerList getNextAnswer() { | |
return this.nextAnswer; | |
} | |
public String getAnswer() { | |
return answer; | |
} | |
} | |
private static class Range { | |
public BigDecimal min, max; | |
public boolean includeMin, includeMax; | |
} | |
// 操作を元に戻す | |
private static Range getRange(BigDecimal value, int digit, String operation) { | |
BigDecimal delta = BigDecimal.ONE.divide(BigDecimal.TEN.pow(digit)); | |
Range ret = null; | |
if (operation.equals("四捨五入")) { | |
ret = new Range(); | |
ret.min = value.subtract(delta.multiply(new BigDecimal(5))); | |
ret.includeMin = true; | |
ret.max = value.add(delta.multiply(new BigDecimal(5))); | |
ret.includeMax = false; | |
} else if (operation.equals("切り上げ")) { | |
ret = new Range(); | |
ret.min = value.subtract(delta.multiply(BigDecimal.TEN)); | |
ret.includeMin = false; | |
ret.max = value; | |
ret.includeMax = true; | |
} else if (operation.equals("切り捨て")) { | |
ret = new Range(); | |
ret.min = value; | |
ret.includeMin = true; | |
ret.max = value.add(delta.multiply(BigDecimal.TEN)); | |
ret.includeMax = false; | |
} | |
return ret; | |
} | |
// 余分なゼロを消す | |
private static String zeroSuppress(String value) { | |
if (value == null || value.indexOf('.') < 0) return value; | |
return value.replaceFirst("\\.?0+$", ""); | |
} | |
public static String solve(String[] query, String id) { | |
int digit1 = Integer.parseInt(query[0]); | |
String operation1 = query[1]; | |
BigDecimal multiplier = new BigDecimal(query[2]); | |
int digit2 = Integer.parseInt(query[3]); | |
String operation2 = query[4]; | |
BigDecimal calcResult = new BigDecimal(query[5]); | |
// 計算する桁数(わからないので余裕を持たせる) | |
int enoughDigit = (digit1 >= digit2 ? digit1 : digit2) * 100; | |
MathContext mc = new MathContext(enoughDigit); | |
if (multiplier.signum() <= 0 || calcResult.signum() < 0) { | |
return "負数は非対応です"; | |
} | |
if (digit1 <= 0 || digit2 <= 0) { | |
return "桁数が不正です"; | |
} | |
// 最後の操作を元に戻す | |
BigDecimal number2rem = BigDecimal.ONE.divide(BigDecimal.TEN.pow(digit2 - 1)); | |
if (calcResult.remainder(number2rem).compareTo(BigDecimal.ZERO) != 0) { | |
// 例 : 小数第1位を切り捨てすると0.24になる数は存在しない(T10) | |
if (id != null) { | |
System.err.println("警告 : " + id + "で後の" + operation2 + "の結果が不正です"); | |
} | |
return "なし"; | |
//return "後の" + operation2 + "の結果が不正です"; | |
} | |
Range range = getRange(calcResult, digit2, operation2); | |
if (range == null) { | |
return "後の演算の種類が不正です"; | |
} | |
// 掛け算を元に戻す | |
range.min = range.min.divide(multiplier, mc); | |
range.max = range.max.divide(multiplier, mc); | |
// 最初の操作後の範囲を求める | |
BigDecimal number1 = BigDecimal.ONE.divide(BigDecimal.TEN.pow(digit1 - 1)); | |
BigDecimal rangeMinRemainder, rangeMaxRemainder; | |
rangeMinRemainder = range.min.remainder(number1); | |
rangeMaxRemainder = range.max.remainder(number1); | |
if (rangeMinRemainder.compareTo(BigDecimal.ZERO) != 0) { | |
range.min = range.min.subtract(rangeMinRemainder).add(number1); | |
range.includeMin = true; | |
} | |
if (rangeMaxRemainder.compareTo(BigDecimal.ZERO) != 0) { | |
range.max = range.max.subtract(rangeMaxRemainder); | |
range.includeMax = true; | |
} | |
// さらに範囲を調整する | |
if (!range.includeMin) { | |
range.min = range.min.add(number1); | |
} | |
if (!range.includeMax) { | |
range.max = range.max.subtract(number1); | |
} | |
// 最終的な範囲を決定する | |
Range minRange = getRange(range.min, digit1, operation1); | |
Range maxRange = getRange(range.max, digit1, operation1); | |
int compare = minRange.min.compareTo(maxRange.max); | |
if (compare > 0 || (compare == 0 && (!minRange.includeMin || !maxRange.includeMax))) { | |
return "なし"; | |
} else { | |
return zeroSuppress(minRange.min.toPlainString()) + | |
(minRange.includeMin ? "以上" : "より大きく") + | |
zeroSuppress(maxRange.max.toPlainString()) + | |
(maxRange.includeMax ? "以下" : "未満"); | |
} | |
} | |
public static void main(String args[]) { | |
boolean testMode = false; | |
boolean warnForInvalidResult = false; | |
for (int i = 0; i < args.length; i++) { | |
if (args[i].equals("--test") || args[i].equals("-t")) { | |
testMode = true; | |
} else if (args[i].equals("--warn") || args[i].equals("-w")) { | |
warnForInvalidResult = true; | |
} | |
} | |
Scanner sc = new Scanner(System.in); | |
AnswerList answerNode = null; | |
AnswerList lastAnswerNode = null; | |
while(sc.hasNextLine()) { | |
// データを読み込む | |
String[] lineData = sc.nextLine().split("\t"); | |
if (lineData.length != 8) continue; | |
String id = lineData[0]; | |
String expectedAnswer = lineData[7]; | |
String[] query = new String[6]; | |
for (int i = 0; i < 6; i++) query[i] = lineData[i + 1]; | |
if (testMode && !id.startsWith("T")) continue; | |
// 問題を解く | |
String answer; | |
try { | |
answer = solve(query, warnForInvalidResult ? id : null); | |
} catch(Exception e) { | |
answer = e.toString(); | |
e.printStackTrace(); | |
} | |
// 一致していなければリストに加える | |
if (!expectedAnswer.equals(answer)) { | |
System.err.println(id + " : expected " + expectedAnswer + ", got " + answer); | |
AnswerList nextAnswer = new AnswerList(id); | |
if (lastAnswerNode == null) { | |
// リストの先頭を設定する | |
answerNode = lastAnswerNode = nextAnswer; | |
} else { | |
// リストの末尾に追加する | |
lastAnswerNode.setNextAnswer(nextAnswer); | |
lastAnswerNode = nextAnswer; | |
} | |
} | |
} | |
System.err.println(); | |
// 結果を出力する | |
if (answerNode != null) { | |
int answerCount = 1; | |
System.out.print(answerNode.getAnswer()); | |
for (AnswerList itr = answerNode.getNextAnswer(); itr != null; itr = itr.getNextAnswer()) { | |
System.out.print("," + itr.getAnswer()); | |
answerCount++; | |
} | |
System.out.println(); | |
System.err.println("" + answerCount + " mismatch(es) found."); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment