以下,複数のファイル構成になっていますので,ファイル間の 区切りを「---・・・」で示します.  このプログラムでは,計算結果を書式指定して出力できるようになっています. ------------------------class Q------------------- /**********************************/ /* 簡単な待ち行列問題(M/M/s)*/ /* coded by Y.Suganuma */ /**********************************/ import java.io.*; public class Q { /*******************/ /* mainprogram */ /*******************/ public static void main(String args[]) throws IOException { int s, seed; double end, m_a, m_s; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); /* 入力データ */ System.out.print("窓口の数は? "); s = Integer.parseInt(in.readLine()); System.out.print("シミュレーション終了時間? "); end = Double.parseDouble(in.readLine()); System.out.print(" 到着時間間隔の平均値は? "); m_a = Double.parseDouble(in.readLine()); System.out.print(" サービス時間の平均値は? "); m_s = Double.parseDouble(in.readLine()); System.out.print("乱数の初期値は? "); seed = Integer.parseInt(in.readLine()); /* システムの定義 */ Q_base base = new Q_base (s, m_a, m_s, end, seed); /* シミュレーションの実行 */ base.Control(); /* 出力 */ base.Output(); } } ------------------------class Q_base-------------- /***************************/ /* クラスQ_baseの定義 */ /***************************/ import java.io.*; import java.util.Random; class Q_base { private int s; // 窓口の数 private int asb; // 全窓口の空き状況 // =0 : すべての窓口がふさがっている // =n : n個の窓口が空いている private int [] sb; // 各窓口の空き状況 // =0 : 窓口は空いている // >0 : サービスを受けている客番号 private double asb_t; // すべての窓口がふさがった時間 private double c_asb; // すべての窓口がふさがっている時間の累計 private double [] c_sb; // 各窓口がふさがっている時間の累計 private double [] st_e; // 各窓口のサービス終了時間 private double [] st_s; // 各窓口がふさがった時間 private int lq; // 現在の待ち行列の長さ private int m_lq; // 最大待ち行列長 private int tq; // 待ち行列の先頭にいる客番号 private double c_lq_t; // 待ち行列長にその長さが継続した時間を乗じた値の累計 private double c_wt; // 待ち時間の累計 private double lq_t; // 現在の待ち行列長になった時間 private double m_wt; // 最大待ち時間 private int sc; // 現在の系内客数 private double c_sc_t; // 系内客数にその数が継続した時間を乗じた値の累計 private double c_sys; // 滞在時間の累計 private double m_sys; // 最大滞在時間 private double sc_t; // 現在の系内客数になった時間 private int m_sc; // 最大系内客数 private double m_a; // 到着時間間隔の平均値 private double m_s; // サービス時間の平均値 private double at; // 次の客の到着時間(負の時は,終了) private double p_time; // 現在時間 private double end; // シミュレーション終了時間 private int nc; // 到着客数カウンタ private Random rn; // 乱数 /*********************************************/ /* コンストラクタ */ /* s_i : 窓口の数 */ /* m_a_i : 到着時間間隔の平均値 */ /* m_s_i : サービス時間の平均値 */ /* end_i : シミュレーション終了時間 */ /* seed : 乱数の初期値 */ /*********************************************/ Q_base (int s_i, double m_a_i, double m_s_i, double end_i, int seed) { int i1; /* 設定 */ s = s_i; m_a = m_a_i; m_s = m_s_i; end = end_i; /* 領域の確保 */ sb = new int [s]; c_sb = new double [s]; st_e = new double [s]; st_s = new double [s]; for (i1 = 0; i1 < s; i1++) { sb[i1] = 0; c_sb[i1] = 0.0; } /* 初期設定 */ p_time = 0.0; nc = 0; asb = s; lq = 0; sc = 0; m_lq = 0; m_sc = 0; c_asb = 0.0; c_wt = 0.0; m_wt = 0.0; c_lq_t = 0.0; lq_t = 0.0; m_sys = 0.0; c_sys = 0.0; c_sc_t = 0.0; sc_t = 0.0; /* 乱数の初期設定 */ rn = new Random(seed); /* 最初の客の到着時間の設定 */ at = p_time + Next_at(); } /**************************************/ /* 次の客の到着までの時間の発生 */ /**************************************/ double Next_at() { return -m_a * Math.log(rn.nextDouble()); } /****************************/ /* サービス時間の発生 */ /****************************/ double Next_sv() { return -m_s * Math.log(rn.nextDouble()); } /******************/ /* 全体の制御 */ /******************/ void Control() { int sw = 0; Customer ct = new Customer (); while (sw > -2) { // 次の処理の選択 sw = Next(); if (sw == -1) // シミュレーションの終了 sw = End_o_s(); // シミュレーション else { if (sw == 0) // 客の到着処理 Arrive(ct); else // サービスの終了 Service(sw, ct); } } } /********************************************************/ /* 次の処理の決定 */ /* return : =-1 : シミュレーションの終了 */ /* =0 : 客の到着処理 */ /* =i : i番目の窓口のサービス終了 */ /********************************************************/ int Next() { int i1, sw; double t; sw = -1; t = end; if (at >= 0.0 && at < t) { sw = 0; t = at; } for (i1 = 0; i1 < s; i1++) { if (sb[i1] > 0 && st_e[i1] <= t) { sw = i1+1; t = st_e[i1]; } } return sw; } /**************************************/ /* 終了処理 */ /* return : =-1 : 終了前処理 */ /* =-2 : 実際の終了 */ /**************************************/ int End_o_s() { int i1, sw; sw = -2; p_time = end; at = -1.0; for (i1 = 0; i1 < s; i1++) { if (sb[i1] > 0) { if (sw == -2) { sw = -1; end = st_e[i1]; } else { if (st_e[i1] > end) end = st_e[i1]; } } } return sw; } /********************************/ /* 客の到着処理 */ /* ct : 客リストの先頭 */ /********************************/ void Arrive(Customer ct) { int i1, k; Customer ct_p; /* 客数の増加と次の客の到着時刻の設定 */ nc += 1; p_time = at; at = p_time + Next_at(); // 次の客 /* 系内客数の処理 */ sc += 1; c_sc_t += (double)(sc - 1) * (p_time - sc_t); sc_t = p_time; if (sc > m_sc) m_sc = sc; /* 待ち行列があるか、または、窓口に空きがない場合 */ if (lq > 0 || asb == 0) { ct_p = new Customer (nc, -1, p_time); ct.Add(ct_p); // 客の登録 lq += 1; if (lq == 1) tq = nc; c_lq_t += (double)(lq - 1) * (p_time - lq_t); lq_t = p_time; if (lq > m_lq) m_lq = lq; } /* すぐサービスをうけれる場合 */ else { k = -1; for (i1 = 0; i1 < s && k < 0; i1++) { if (sb[i1] == 0) { ct_p = new Customer (nc, i1, p_time); ct.Add(ct_p); // 客の登録 k = i1; sb[k] = nc; st_e[k] = p_time + Next_sv(); asb -= 1; } } st_s[k] = p_time; if (asb == 0) asb_t = p_time; } } /*************************************/ /* サービス終了時の処理 */ /* k : サービス終了窓口番号 */ /* ct : 客リストの先頭 */ /*************************************/ void Service(int k, Customer ct) { int i1; double x1; /* 時間の設定 */ k -= 1; p_time = st_e[k]; /* 系内客数の処理 */ sc -= 1; c_sc_t += (double)(sc + 1) * (p_time - sc_t); sc_t = p_time; /* 滞在時間の処理 */ x1 = p_time - ct.Search(sb[k]); c_sys += x1; if (x1 > m_sys) m_sys = x1; ct.Del(sb[k]); // 客の削除 /* 窓口使用時間の処理 */ asb += 1; sb[k] = 0; c_sb[k] += (p_time - st_s[k]); /* 待ち行列がある場合 */ if (lq > 0) { asb -= 1; lq -= 1; c_lq_t += (double)(lq + 1) * (p_time - lq_t); lq_t = p_time; x1 = p_time - ct.Search(tq); c_wt += x1; if (x1 > m_wt) m_wt = x1; k = -1; for (i1 = 0; i1 < s && k < 0; i1++) { if (sb[i1] == 0) { k = i1; sb[k] = tq; st_e[k] = p_time + Next_sv(); st_s[k] = p_time; ct.Change(tq, k); } } if (lq > 0) tq = ct.Search(); } /* 待ち行列がない場合 */ else { if (asb == 1) c_asb += (p_time - asb_t); } } /****************************/ /* 結果の出力 */ /* (カッコ内は理論値) */ /****************************/ void Output() { int i1; double L, Lq, myu, p0, pi, ram, rn, rou, rs, W, Wq; String s1, s2, s3; rn = (double)nc; rs = (double)s; ram = 1.0 / m_a; myu = 1.0 / m_s; rou = ram / (rs * myu); if (s == 1) { p0 = 1.0 - rou; pi = rou; } else { p0 = 1.0 / (1.0 + 2.0 * rou + 4.0 * rou * rou / (2.0 * (1.0 - rou))); pi = 4.0 * rou * rou * p0 / (2.0 * (1.0 - rou)); } Lq = pi * rou / (1.0 - rou); L = Lq + rs * rou; Wq = Lq / ram; W = Wq + 1.0 / myu; s1 = Format.Edit(p_time, 0, 2, 10); s2 = Format.Edit(rou, 0, 5, 10); s3 = Format.Edit(p0, 0, 5, 10); System.out.println("シミュレーション終了時間=" + s1 + " 客数=" + nc + " ρ=" + s2 + " p0=" + s3); s1 = Format.Edit(c_asb/p_time, 0, 3, 5); s2 = Format.Edit(pi, 0, 5, 10); System.out.print(" すべての窓口が塞がっている割合=" + s1 + " (" + s2 + ")\n"); System.out.print(" 各窓口が塞がっている割合\n"); for (i1 = 0; i1 < s; i1++) { s1 = Format.Edit(i1+1, 3); s2 = Format.Edit(c_sb[i1]/p_time, 0, 3, 5); System.out.println(" " + s1 + " " + s2); } s1 = Format.Edit(c_lq_t/p_time, 0, 3, 7); s2 = Format.Edit(Lq, 0, 5, 10); s3 = Format.Edit(m_lq, 3); System.out.println(" 平均待ち行列長=" + s1 + " (" + s2 + ") 最大待ち行列長=" + s3); s1 = Format.Edit(c_sc_t/p_time, 0, 3, 7); s2 = Format.Edit(L, 0, 5, 10); s3 = Format.Edit(m_sc, 3); System.out.println(" 平均系内客数 =" + s1 + " (" + s2 + ") 最大系内客数 =" + s3); s1 = Format.Edit(c_wt/rn, 0, 2, 7); s2 = Format.Edit(Wq, 0, 5, 10); s3 = Format.Edit(m_wt, 0, 2, 7); System.out.println(" 平均待ち時間 =" + s1 + " (" + s2 + ") 最大待ち時間 =" + s3); s1 = Format.Edit(c_sys/rn, 0, 2, 7); s2 = Format.Edit(W, 0, 5, 10); s3 = Format.Edit(m_sys, 0, 2, 7); System.out.println(" 平均滞在時間 =" + s1 + " (" + s2 + ") 最大滞在時間 =" + s3); } } ------------------------class Customer------------ /****************************/ /* クラスCustomerの定義 */ /****************************/ class Customer { private double time; // 到着時刻 private int num; // 客番号 private int state; // 客の状態 // =-1 : 待ち行列に入っている // >=0 : サービスを受けている窓口番号 private Customer next; /***********************/ /* コンストラクタ */ /* n : 客番号 */ /* s : 状態 */ /***********************/ Customer (int n, int s, double t) { time = t; num = n; state = s; next = null; } /********************************/ /* 引数無しのコンストラクタ */ /********************************/ Customer () { next = null; } /**********************************************/ /* 客をリストの最後に追加 */ /* dt : Customerクラスのオブジェクト */ /**********************************************/ void Add(Customer dt) { Customer lt = this; while (lt.next != null) lt = lt.next; lt.next = dt; } /***********************/ /* 状態の変更 */ /* n : 客番号 */ /* s : 状態 */ /***********************/ void Change(int n, int s) { Customer lt = this; int sw = 1; while (sw > 0) { // データが存在しない場合 if (lt.next == null) { System.out.print(" 指定されたデータがありません(Change)!\n"); System.exit(1); } // 比較し,変更 else { lt = lt.next; if (n == lt.num) { lt.state = s; sw = 0; } } } } /***********************/ /* 客の削除 */ /* n : 客番号 */ /***********************/ void Del(int n) { Customer lt1, lt2 = this; int sw = 1; while (sw > 0) { // データが存在しない場合 if (lt2.next == null) { System.out.print(" 指定されたデータがありません(Del)!\n"); System.exit(1); } // 比較し,削除 else { lt1 = lt2; lt2 = lt2.next; if (n == lt2.num) { lt1.next = lt2.next; sw = 0; } } } } /**************************************/ /* 待ち行列の先頭の客を捜す */ /* return : 先頭の客番号 */ /* (負の時は無し) */ /**************************************/ int Search() { Customer lt = this; int n = -1; while (n < 0) { // データが存在しない場合 if (lt.next == null) { System.out.print(" 指定されたデータがありません(Search_q)!\n"); System.exit(1); } // 探索 else { lt = lt.next; if (lt.state < 0) n = lt.num; } } return n; } /******************************/ /* 指定した客の到着時間 */ /* nm : 客番号 */ /* return : 到着時間 */ /******************************/ double Search(int nm) { Customer lt = this; double t = 0.0; int sw = -1; while (sw < 0) { // データが存在しない場合 if (lt.next == null) { System.out.print(" 指定されたデータがありません(Search)!\n"); System.exit(1); } // 探索 else { lt = lt.next; if (lt.num == nm) { sw = 0; t = lt.time; } } } return t; } } ------------------------class Format-------------- /**************************/ /* クラスFormatの定義 */ /**************************/ class Format { /***************************************************/ /* 整数を指定した長さの文字列に変換 */ /* data : 整数データ */ /* n : 文字列の長さ */ /* return : 文字列 */ /* 左側を空白で埋める */ /* 長すぎるときは「*」で埋める */ /***************************************************/ static String Edit(int data, int n) { int i1, len; String str; str = String.valueOf(data); len = str.length(); if (len != n) { // 長さが短い if (len < n) { for (i1 = 0; i1 < n-len; i1++) str = " " + str; } // 長さが長すぎる else { char c[] = new char [n]; for (i1 = 0; i1 < n; i1++) c[i1] = '*'; str = String.copyValueOf(c); } } return str; } /***************************************************/ /* 実数を指定した長さの文字列に変換 */ /* (オーバーフローのチェックは行っていない) */ /* data : 実数データ */ /* sw : 表現方法 */ /* =0 : ±xxxx.xx */ /* =1 : ±x.xxxxxE±xxx */ /* p : 小数点以下の桁数 */ /* n : 文字列の長さ */ /* return : 文字列 */ /* 必要なら空白または0で埋める */ /* 長すぎるときは「*」で埋める */ /***************************************************/ static String Edit(double data, int sw, int p, int n) { double x; int i1, k, k1, len; String str, s1, s2, s3; str = String.valueOf(data); // 元のデータの文字列表現 /* 固定小数点表示 */ if (sw == 0) { // 入力データが固定小数点表示の場合 if (str.indexOf('E') < 0 && str.indexOf('e') < 0) { // 小数点以上と以下を取り出す k = str.indexOf('.'); s1 = str.substring(0, k); s2 = str.substring(k+1); // 全体の文字列の作成 str = Append(data, p, n, s1, s2); } // 入力データが浮動小数点表示の場合 else { // 仮数部と指数部 k = str.indexOf('E'); if (k < 0) k = str.indexOf('e'); s1 = str.substring(0, k); s2 = str.substring(k+1); // 指数部の値 k1 = Integer.parseInt(s2); // 仮数部の小数点以上と以下 k = s1.indexOf('.'); s2 = s1.substring(k+1); s1 = s1.substring(0, k); // 小数点以上と以下の調整 if (k1 != 0) { if (k1 > 0) { len = s2.length(); if (k1 == len) { s1 += s2; s2 = "0"; } else { if (k1 < len) { s1 += s2.substring(0, k1-1); s2 = s2.substring(k1); } else { s1 += s2; for (i1 = 0; i1 < k1-len; i1++) s1 += "0"; s2 = "0"; } } } else { len = s1.length(); k1 = -k1; if (k1 == len) { s2 = s1 + s2; s1 = "0"; } else { if (k1 < len) { s2 = s1.substring(len-k1) + s2; s1 = s1.substring(0, len-k1); } else { s2 = s1 + s2; for (i1 = 0; i1 < k1-len; i1++) s2 = "0" + s2; s1 = "0"; } } } } // 全体の文字列の作成 str = Append(data, p, n, s1, s2); } } /* 浮動小数点表示 */ else { // 入力データが固定小数点表示の場合 if (str.indexOf('E') < 0 && str.indexOf('e') < 0) { // 指数部と仮数部を決める k1 = 0; x = Math.abs(data); if (x >= 10.0) { while (x >= 10.0) { x /= 10.0; k1++; } } else { if (x < 1.0) { while (x < 1.0) { x *= 10.0; k1--; } } } // 指数部の調整 if (k1 >= 0) { s3 = String.valueOf(k1); len = s3.length(); if (len < 3) { for (i1 = 0; i1 < 3-len; i1++) s3 = "0" + s3; } s3 = "+" + s3; } else { s3 = String.valueOf(-k1); len = s3.length(); if (len < 3) { for (i1 = 0; i1 < 3-len; i1++) s3 = "0" + s3; } s3 = "-" + s3; } // 仮数部の小数点以上と以下 str = String.valueOf(x); k = str.indexOf('.'); s1 = str.substring(0, k); s2 = str.substring(k+1); // 仮数部の調整 str = Append(x, p, n-5, s1, s2); // 桁数オーバー k = str.indexOf('*'); if (k >= 0) { for (i1 = 0; i1 < 5; i1++) str += "*"; } // 全体の文字列 else str = str + "E" + s3; } // 入力データが浮動小数点表示の場合 else { // 仮数部と指数部 k = str.indexOf('E'); if (k < 0) k = str.indexOf('e'); s1 = str.substring(0, k); s2 = str.substring(k+1); x = Double.parseDouble(s1); // 指数部の調整 k1 = Integer.parseInt(s2); if (k1 >= 0) { s3 = String.valueOf(k1); len = s3.length(); if (len < 3) { for (i1 = 0; i1 < 3-len; i1++) s3 = "0" + s3; } s3 = "+" + s3; } else { s3 = String.valueOf(-k1); len = s3.length(); if (len < 3) { for (i1 = 0; i1 < 3-len; i1++) s3 = "0" + s3; } s3 = "-" + s3; } // 仮数部の小数点以上と以下 k = s1.indexOf('.'); s2 = s1.substring(k+1); s1 = s1.substring(0, k); // 仮数部の調整 str = Append(x, p, n-5, s1, s2); // 桁数オーバー k = str.indexOf('*'); if (k >= 0) { for (i1 = 0; i1 < 5; i1++) str += "*"; } // 全体の文字列 else str = str + "E" + s3; } } return str; } /************************************************************/ /* 小数点以上,及び,以下の文字列から全体の文字列を作成 */ /* data : 実数データ */ /* p : 小数点以下の桁数 */ /* n : 文字列の長さ */ /* s1 : 小数点以上の文字列 */ /* s2 : 小数点以下の文字列 */ /* return : 文字列 */ /************************************************************/ static String Append(double data, int p, int n, String s1, String s2) { long L; int i1, k, len; String str; // 小数点以下の桁数の調整 if (p == 0) { L = (long)data; if ((data-(double)L) >= 0.5) { L = Long.parseLong(s1) + 1; s1 = String.valueOf(L); } } else { len = s2.length(); if (len != p) { if (len < p) { for (i1 = 0; i1 < p-len; i1++) s2 += "0"; } else { L = Long.parseLong(s2.substring(0, p)); k = Integer.parseInt(s2.substring(p, p+1)); if (k >= 5) L++; s2 = String.valueOf(L); } } } // 全体の長さの調整 if (p == 0) str = s1; else str = s1 + "." + s2; len = str.length(); if (len != n) { if (len < n) { for (i1 = 0; i1 < n-len; i1++) str = " " + str; } else { char c[] = new char [n]; for (i1 = 0; i1 < n; i1++) c[i1] = '*'; str = String.copyValueOf(c); } } return str; } }