ACMの過去問解いてみた!!(3)〜2007年国内予選ProblemB
PCの利用時間を出す問題。
重複の判定がなかなかできなくて、時間かかりました。
package acm2007.b; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; public class Q { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(Q.class .getResourceAsStream("input.txt")));
ここまではいつもの入出力。
String line = null; while ((line = br.readLine()) != null) { String[] str = line.split(" "); int n = Integer.parseInt(str[0]); // PCの数 int m = Integer.parseInt(str[1]); // 学生数 if (n == 0 && m == 0) { break; }
PCの数、学生の数を変数に代入。
終了条件を記述。
int r = Integer.parseInt(br.readLine()); // 利用記録数 int rSet[][] = new int[r / 2 + 1][4]; // 利用記録セット int p = 0; HashMap<String, Integer> map = new HashMap<String, Integer>(); for (int i = 0; i < r; i++) { line = br.readLine(); str = line.split(" "); if (map.get(str[1] + "-" + str[2]) != null) { rSet[p][0] = Integer.parseInt(str[1]); // PC番号 rSet[p][1] = Integer.parseInt(str[2]); // 学生番号 rSet[p][2] = map.get(str[1] + "-" + str[2]); // ログイン時間 rSet[p][3] = Integer.parseInt(str[0]); // ログアウト時間 p++; map.remove(str[1] + "-" + str[2]); //次のPC−学生の同じ組が入るときのために削除 } else { map.put(str[1] + "-" + str[2], Integer.parseInt(str[0])); } }
利用記録を配列に代入します。
HashMapを使って、PC番号-学生番号をキーにしてログイン、ログアウトの時間を一緒に記録する。
int q = Integer.parseInt(br.readLine()); // 質問数 int qSet[][] = new int[q][3]; // 質問セット for (int i = 0; i < q; i++) { line = br.readLine(); str = line.split(" "); for (int j = 0; j < 3; j++) { qSet[i][j] = Integer.parseInt(str[j]); } }
質問を配列に代入します。
for (int i = 0; i < q; i++) { int fill[] = new int[1260]; // 塗りつぶし用 int sum = 0; // カウント用 for (int j = 0; j < p; j++) { if (qSet[i][2] == rSet[j][1]) { // 学生番号が同じ for (int k = rSet[j][2]; k < rSet[j][3]; k++) { //利用している時間を塗りつぶす fill[k] += 1; } } }
”540 ≤ t ≤ 1260”とあるので1260の配列を宣言します。利用している”分”を1ずつインクリメントしていきます。こうすることで、PCの重複の利用を無視出来ます。
for (int l = qSet[i][0]; l < qSet[i][1]; l++) { //クエスチョンの時間の範囲を指定 if (fill[l] != 0) { //0じゃなかったら利用時間に加算 sum += 1; } } System.out.println(sum); } } } }
配列を走査し、中身が0じゃないものを数えていきます。
この1問にかなり時間をかけていしまったのですが、結局かなり奇妙なプログラムになってしまいました。
Javaでの別のやり方を見てみたいんだが、、、
ACMの過去問解いてみた!!(2)
前回に引き続き、ACMの過去問を、、、。もちろんJavaです。
ProblemA 等しい合計点
太郎と花子がカードを交換する問題です。
とりあえず入力の処理から。
public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(Q.class .getResourceAsStream("input.txt"))); String line = null; while ((line = br.readLine()) != null) {
ここまでで、ファイルの入ったインプットをとりあえず一行ずつ読み込みます。
String[] str = line.split(" "); int n = Integer.parseInt(str[0]); // 太郎のカードの枚数 int m = Integer.parseInt(str[1]); // 花子のカードの枚数 int numTaro[] = new int[n]; // 太郎の持っているカードの点数 int numHanako[] = new int[m]; // 花子の持っているカードの点数 int cNum[] = { 100, 100 }; //交換が等しくなるカードの組み合わせ
line.splitでそれぞれのカードの枚数を読み込みます。
それから点数を入れる用の変数を作り,出力用の答えを入れる変数を作ります。これには,問題文に”合計を等しくするようなカードの交換の方法が複数ある場合は, 交換するカードの点数の和が最小となるものを出力すること.”とあるので、とりあえず一番大きい100を入れておきます。
for (int i = 0; i < n + m; i++) { line = br.readLine(); if (i < n) { numTaro[i] = Integer.parseInt(line); } else { numHanako[i - n] = Integer.parseInt(line); } } if (n == 0 && m == 0) {//終了条件 break; }
カードの枚数の分だけそれぞれの配列に入れていきます。
終了条件もここに記述しておきます。
for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { int changeCard = 0; //カード交換用の変数 changeCard = numTaro[i]; numTaro[i] = numHanako[j]; numHanako[j] = changeCard;
いよいよ本題です。
一つづつカードを交換します。
if (sumArray(numTaro) == sumArray(numHanako)) { //sumArray:合計用のメソッド if (numHanako[j] + numTaro[i] < cNum[0] + cNum[1]) { cNum[0] = numHanako[j]; cNum[1] = numTaro[i]; } } numHanako[j] = numTaro[i]; numTaro[i] = changeCard; } }
それから合計用のメソッドを呼び出し、もし"合計が等しい"かつ"今までの組み合わせの和より小さい"ならば答えを入れ替えます。
それから次の交換のためにカードをもとに戻します。この処理を全ての組み合わせで行います。
if (cNum[0] == 100 && cNum[1] == 100) { System.out.println(-1); } else { System.out.println(cNum[0] + " " + cNum[1]); cNum[0] = 100; cNum[1] = 100; } } }
最後に出力部分です。
もし100,100のままなら、交換されていないので-1を、それ以外ならカードの組み合わせを出力します。
private static int sumArray(int x[]) { int sum = 0; for (int s : x) { sum = sum + s; } return sum; } }
一応、合計用のメソッドです。
今日はこんな感じで。このくらいの問題は慣れてきた...。
ACMの過去問解いてみた!(1) 〜2009年国内予選ProblemA
来月のACMに向けてJava で去年の過去問解いてみた。
2009年度東京大会 国内予選問題
ProblemA
素直に解いただけ…。
次期町長を決める問題です。
package acm2009.a; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class Q { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(Q.class .getResourceAsStream("input.txt"))); String line = null; while ((line = br.readLine()) != null) {
ファイルの入出力を行います。
String[] str = line.split(" "); int n = Integer.parseInt(str[0]); //候補者の総数 int p = Integer.parseInt(str[1]); //最初に碗に入れる小石の総数 if (n == 0 && p == 0) { break; } System.out.println(game(n, p)); } }
候補者の人数と小石の人数を入れる変数を作り、終了条件を記述します。
あとはメソッドに渡して返り値を出力します。
private static int game(int n, int p) { int wan = p; //碗に入っている小石の数 int[] numstorn = new int[n]; //候補者が持っている小石の数 while (true) { for (int i = 0; i < n; i++) { if (wan == 0) { wan = numstorn[i]; numstorn[i] = 0; } else { wan--; numstorn[i]++; if (p == numstorn[i]) { //小石の総数と候補者が持っている小石の数が等しければ終了。 return i; } } } } } }
問題通りに書いていけば、いけます。
Hello World!!
はろーはてな。ブログはじめます。