Skip to content

Instantly share code, notes, and snippets.

@kazasiki
Last active August 29, 2015 14:01
Show Gist options
  • Save kazasiki/78c6a4c392cc009f755f to your computer and use it in GitHub Desktop.
Save kazasiki/78c6a4c392cc009f755f to your computer and use it in GitHub Desktop.
CodeIQにて結城浩さん出題「チケットゴブル問題」の解答用コード。TicketGobble.javaがmainをもつクラスです。
package package01;
/**
* 航空チケット。
*/
public class Ticket {
/**
* 国名
*/
public final String country;
/**
* 出発日
*/
public final int departure;
/**
* 到着日
*/
public final int arrival;
/**
* 出力文字列
*/
private final String OutputStr;
/**
* 国名、出発日、到着日を設定する
*
* @param country 国名
* @param departure 出発日
* @param arrival 到着日
*/
Ticket(String country, int departure, int arrival) {
this.country = country;
this.departure = departure;
this.arrival = arrival;
// 出力用の文字列を生成
StringBuilder sb = new StringBuilder(country);
sb.append(" ");
calToSb(sb, departure);
sb.append("-");
calToSb(sb, arrival);
OutputStr = sb.toString();
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
return OutputStr;
}
/**
* 日付を文字列に変換する
*
* @param sb
* @param cal
*/
private void calToSb(StringBuilder sb, int cal) {
sb.append(cal/100+1);
sb.append("/");
sb.append(cal%100);
}
}
package package01;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class TicketFileInput {
// private static final Path inputFile = Paths.get("five.txt");
private static final Path inputFile = Paths.get("tickets.txt");
/**
* 国名と日付の区切り文字
*/
private static final String COUNTRY_SEPARATE_STR = " ";
/**
* 開始日付と終了日付の区切り文字
*/
private static final String DATE_SEPARATE_STR = "-";
/**
* 日付中の月と日の区切り文字
*/
private static final String DAY_SEPARATE_STR = "/";
/**
* inputFileで指定されたファイルのチケット情報を読み込む。<br>
* 読込結果はチケット型のリストで返却する。<br>
*
* @return 読込結果のリスト
*/
public static List<Ticket> parseFile() {
List<Ticket> ticketsList = new ArrayList<>();
try {
BufferedReader br = Files.newBufferedReader(inputFile, Charset.defaultCharset());
String str = br.readLine();
while (str != null) {
ticketsList.add(getTicket(str));
str = br.readLine();
}
} catch (IOException e) {
e.printStackTrace();
}
return ticketsList;
}
/**
* 1行のテキストをチケット型のインスタンスに変換する
*
* @param value 一行テキスト
* @return 変換結果のインスタンス
*/
private static Ticket getTicket(String value) {
// 1行テキストから国名を取り出す
String[] splitText = value.split(COUNTRY_SEPARATE_STR);
String country = splitText[0];
// 分割したテキストから日付を取り出す
splitText = splitText[1].split(DATE_SEPARATE_STR);
String departure = splitText[0];
String arrival = splitText[1];
int departureCal = getCalendar(departure);
int arrivalCal = getCalendar(arrival);
return new Ticket(country, departureCal, arrivalCal);
}
/**
* 日付の文字列を4桁の整数型に変換する。
*
* @param dateString 日付の文字列
* @return 変換後の4桁の整数型
*/
private static int getCalendar(String dateString) {
String[] splitStr = dateString.split(DAY_SEPARATE_STR);
String monthStr = splitStr[0];
String dayStr = splitStr[1];
int result = (Integer.parseInt(monthStr) - 1) * 100;
result += Integer.parseInt(dayStr);
return result;
}
}
package package01;
import java.util.List;
public class TicketGobble {
public static void main(String[] args) {
// ファイルからチケットの情報を読み取って、リスト型に変換する。
List<Ticket> ticketList = TicketFileInput.parseFile();
// 旅行プランをたてる。
List<Ticket> optList = TicketPlan_Sorting.calcPlan(ticketList);
// 解答用の出力
System.out.println(listToString(optList));
}
/**
* チケットリストを文字列に変換して返却する<br>
* 文字列は「チケットの数:国名(スペース区切り)」となる<br>
*
* @param list チケットのリスト
* @return 「チケットの数:国名(スペース区切り)」の文字列
*/
public static String listToString(List<Ticket> list) {
StringBuilder sb = new StringBuilder((Integer.toString(list.size())));
for (Ticket data : list) {
sb.append(" ").append(data.country);
}
return sb.toString();
}
}
package package01;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* 日付順でのソートによって旅行プランをたてる。<br>
*/
public class TicketPlan_Sorting {
/**
* チケットリストから「できるだけ多くの国に旅行するプラン」を求めて返却する
*
* @param ticketList チケットのリスト
* @return できるだけ多くの国に旅行するプラン
*/
public static List<Ticket> calcPlan(List<Ticket> ticketList) {
// 引数のインスタンスは弄りたくないので、リストをシャローコピー
ArrayList<Ticket> sortedList = new ArrayList<>(ticketList);
// 日付順にソートをかける
Collections.sort(sortedList, TicketComparator.DATE_INSTANCE);
// 解答用のリスト
ArrayList<Ticket> plan = new ArrayList<>(sortedList.size());
for (Ticket data : sortedList) {
if(plan.isEmpty()){
plan.add(data);
} else {
Ticket last = plan.get(plan.size()-1);
if(data.departure > last.arrival){
plan.add(data);
} else if(data.arrival < last.arrival){
plan.remove(last);
plan.add(data);
}
}
}
// 国名順にソートをかける
Collections.sort(plan, TicketComparator.COUNTRY_INSTANCE);
return plan;
}
}
/**
* Ticketクラスの順序付けを行う比較関数です。<br>
* 国名順と日付順のインスタンスを用意しており、staticな定数として提供します。
*/
class TicketComparator implements Comparator<Ticket> {
private static final int SORT_MODE_COUNTRY = 0;
private static final int SORT_MODE_DATE = 1;
/**
* 国名順の比較関数インスタンス。
*/
public static final TicketComparator COUNTRY_INSTANCE = new TicketComparator(SORT_MODE_COUNTRY);
/**
* 日付順の比較関数インスタンス。<br>
* 出発日と到着日では出発日が優先されます。<br>
*/
public static final TicketComparator DATE_INSTANCE = new TicketComparator(SORT_MODE_DATE);
private int sortMode;
private TicketComparator(int sortMode) {
this.sortMode = sortMode;
}
@Override
public int compare(Ticket o1, Ticket o2) {
switch (this.sortMode) {
case SORT_MODE_COUNTRY:
return o1.country.compareTo(o2.country);
case SORT_MODE_DATE:
int result = o1.departure - o2.departure;
if (result == 0)
return o1.arrival - o2.arrival;
else
return result;
default:
return 0;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment