Skip to content

Instantly share code, notes, and snippets.

@mikecat
Created February 1, 2015 00:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikecat/2e599527e675cfc97c14 to your computer and use it in GitHub Desktop.
Save mikecat/2e599527e675cfc97c14 to your computer and use it in GitHub Desktop.
CodeIQ「中学入試から:概数と計算」解答コード
// 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