待ち行列(複雑な例)

/******************************/
/* 複雑な待ち行列問題         */
/*      coded by Y.Suganuma   */
/******************************/
import java.io.*;
import java.util.*;

public class Test {
	/****************/
	/* main program */
	/****************/
	public static void main(String args[]) throws IOException
	{
		BufferedReader inp = new BufferedReader(new InputStreamReader(System.in));
					// 入り口
		System.out.print("入り口(Inlet)の数は? ");
		int n_i = Integer.parseInt(inp.readLine().trim());
		ArrayList <Inlet> inl = new ArrayList <Inlet>();
		for (int i1 = 0; i1 < n_i; i1++) {
			double m_a = 0.0;
			System.out.print((i1+1) + " 番目の入り口(Inlet)\n");
			System.out.print("     名前は? ");
			String name1 = (inp.readLine()).trim();
			ArrayDeque <Double> que = new ArrayDeque <Double>();
			System.out.print("     到着分布(=0:指数分布,1=一定時間間隔,<0:指定:客数の負値))? ");
			int n = Integer.parseInt(inp.readLine().trim());
			if (n == 0) {
				System.out.print("          到着時間間隔の平均値は? ");
				m_a = Double.parseDouble(inp.readLine().trim());
			}
			else if (n == 1) {
				System.out.print("          到着時間間隔は? ");
				m_a = Double.parseDouble(inp.readLine().trim());
			}
			else {
				double x;
				for (int i2 = 0; i2 < -n; i2++) {
					System.out.print("          到着時間は? ");
					x = Double.parseDouble(inp.readLine().trim());
					que.add(x);
				}
			}
			System.out.print("     並ぶ待ち行列の名前は? ");
			String name2 = (inp.readLine()).trim();
			Inlet inl_e = new Inlet(name1, n, m_a, que, name2);
			inl.add(inl_e);
		}
						// 待ち行列
		System.out.print("待ち行列(Queue)の数は? ");
		int n_q = Integer.parseInt(inp.readLine().trim());
		ArrayList <Queue> que = new ArrayList <Queue>();
		for (int i1 = 0; i1 < n_q; i1++) {
			System.out.print((i1+1) + " 番目の待ち行列(Queue)\n");
			System.out.print("     名前は? ");
			String name1 = (inp.readLine()).trim();
			System.out.print("     入り口(0),または,窓口(n>0,窓口の数)から? ");
			int n = Integer.parseInt(inp.readLine().trim());
			ArrayList <String> in = new ArrayList <String>();
			if (n == 0) {
				System.out.print("          入り口の名前は? ");
				String name2 = (inp.readLine()).trim();
				in.add(name2);
			}
			else {
				for (int i2 = 0; i2 < n; i2++) {
					System.out.print("          " + (i2+1) + " 番目の窓口の名前は? ");
					String name3 = (inp.readLine()).trim();
					in.add(name3);
				}
			}
			int m;
			System.out.print("     処理する窓口の数は? ");
			m = Integer.parseInt(inp.readLine().trim());
			ArrayList <String> out = new ArrayList <String>();
			for (int i2 = 0; i2 < m; i2++) {
				System.out.print("          " + (i2+1) + " 番目の窓口の名前は? ");
				String name4 = (inp.readLine()).trim();
				out.add(name4);
			}
			Queue que_e = new Queue(name1, n, in, m, out);
			que.add(que_e);
		}
						// 窓口
		System.out.print("窓口(Entity)の数は? ");
		int n_e = Integer.parseInt(inp.readLine().trim());
		ArrayList <Entity> ent = new ArrayList <Entity>();
		for (int i1 = 0; i1 < n_e; i1++) {
			double m_s = 0.0;
			System.out.print((i1+1) + " 番目の窓口(Entity)\n");
			System.out.print("     名前は? ");
			String name1 = (inp.readLine()).trim();
			System.out.print("     サービス分布(=0:指数分布,1=一定時間)? ");
			int s_t = Integer.parseInt(inp.readLine().trim());
			if (s_t == 0) {
				System.out.print("          サービス時間の平均値は? ");
				m_s = Double.parseDouble(inp.readLine().trim());
			}
			else {
				System.out.print("          サービス時間は? ");
				m_s = Double.parseDouble(inp.readLine().trim());
			}
			System.out.print("     待ち行列(入力)の名前は? ");
			String name2 = (inp.readLine()).trim();
			int sw;
			System.out.print("     終了後,外部(0),または,待ち行列(1)? ");
			sw = Integer.parseInt(inp.readLine().trim());
			String name3 = "";
			if (sw > 0) {
				System.out.print("          待ち行列(出力)の名前は? ");
				name3 = (inp.readLine()).trim();
			}
			Entity ent_e = new Entity(name1, s_t, m_s, name2, sw, name3);
			ent.add(ent_e);
		}
						// 全体の制御を行うクラス
		double end;
		System.out.print("シミュレーション終了時間? ");
		end = Double.parseDouble(inp.readLine().trim());
    	
		Q_base base = new Q_base(inl, que, ent, end);   // 全体の制御を行うクラス
						// 実行
		base.Control();
						// 出力
		base.Output();
	}
}

/*********************/
/* クラスInletの定義 */
/*********************/
class Inlet {
	String name;   // 入り口名
	String out;   // 待ち行列名
	int out_n;   // 待ち行列番号
	double arrive_time;   // 客の到着時刻(負:客がない)
	int a_t;   // = -n : 到着する客の人数を負の値にしたもの
	           // =0 : 指数分布
	           // =1 : 一定時間間隔
	double mean;   // 到着時間間隔またはその平均
	ArrayDeque <Double> que;   // 客の到着時刻リスト

	/*************************************************************/
	/* コンストラクタ                                            */
	/*      name1 : 入り口名                                     */
	/*      a_t1;   // = -n : 到着する客の人数を負の値にしたもの */
	/*              // =0 : 指数分布                             */
	/*              // =1 : 一定時間間隔                         */
	/*      m_a: 到着時間間隔またはその平均                     */
	/*      que1 : 客の到着時刻リスト                            */
	/*      name2 : 待ち行列名                                   */
	/*************************************************************/
	Inlet (String name1, int a_t1, double m_a, ArrayDeque<Double> que1, String name2)
	{
		name = name1;
		out  = name2;
		mean = m_a;
		a_t  = a_t1;
		que  = que1;
		if (a_t == 1)
			arrive_time = 0;
		else if (a_t < 0)
			arrive_time = que.pollFirst().doubleValue();
	}
}

/*********************/
/* クラスQueueの定義 */
/*********************/
class Queue {
	String name;   // 待ち行列名
	int nc;   // 待ち行列への到着客数カウンタ
	int max_q_l;   // 最大待ち行列長
	double c_ql;   // 待ち行列長にその長さが継続した時間を乗じた値の累計
	double ql_t;   // 現在の待ち行列長になった時間
	double max_wt;   // 最大待ち時間
	double c_wt;   // 待ち時間の累計
	int n;   // =0 : 入り口から入る
	         // >0 : 複数の窓口から入る(窓口数)
	ArrayList <String> in;   // 入り口名,または,窓口名
	ArrayList <Integer> in_n;   // 入り口番号,または,窓口番号
	int m;   // 処理する窓口数
	ArrayList <String> out;   // 窓口名
	ArrayList <Integer> out_n;   // 窓口番号
	ArrayDeque <Integer> que;   // 待ち行列

	/*********************************************/
	/* コンストラクタ                            */
	/*      name1 : 待ち行列名                   */
	/*      n1 : =0 : 入り口から入る             */
	/*           >0 : 複数の窓口から入る(窓口数) */
	/*      in1 : 入り口名,または,窓口名       */
	/*      m1 : 処理する窓口数                  */
	/*      out1 : 窓口名                        */
	/*********************************************/
	Queue(String name1, int n1, ArrayList<String> in1, int m1, ArrayList<String> out1)
	{
		name    = name1;
		in      = in1;
		n       = n1;
		in_n    = new ArrayList <Integer>();
		out     = out1;
		m       = m1;
		out_n   = new ArrayList <Integer>();
 		que     = new ArrayDeque <Integer>();
		nc      = 0;
		max_q_l = 0;
		c_ql    = 0.0;
		ql_t    = 0.0;
		max_wt  = 0.0;
		c_wt    = 0.0;
	}
}

/**********************/
/* クラスEntityの定義 */
/**********************/
class Entity {
	String name;   // Entity名
	double busy_t;   // 窓口がふさがった時間
	double c_busy;   // 窓口がふさがっている時間の累計
	double end_time;   // サービス終了時間(負:何も処理していない)
	int s_t;   // =0 : 指数分布
	           // =1 : 一定時間
	double mean;   // 平均サービス時間
	int service;   // サービス中の客番号(0のときはなし)
	String in;   // 待ち行列(入力)の名前
	int in_n;   // 待ち行列(入力)番号
	int to;   // =0 : システムの外に出る
	          // =1 : 待ち行列に入る
	String out;   // 待ち行列(出力)の名前
	int out_n;   // 待ち行列(出力)番号

	/****************************************/
	/* コンストラクタ                       */
	/*      name1 : 窓口名                  */
	/*      s_t1;   // =0 : 指数分布        */
	/*              // =1 : 一定時間        */
	/*      m_s:サービス時間またはその平均 */
	/*      in : 待ち行列(入力)の名前       */
	/*      sw : =0 : システムの外に出る    */
	/*           =1 : 待ち行列に入る        */
	/*      out : 待ち行列(出力)の名前      */
	/****************************************/
	Entity(String name1, int s_t1, double m_s, String name2, int sw, String name3)
	{
		name = name1;
		to   = sw;
		in   = name2;
		if (to > 0)
			out = name3;
		end_time = -1.0;
		s_t      = s_t1;
		mean     = m_s;
		service  = 0;
		busy_t   = -1.0;
		c_busy   = 0.0;
	}
}

/************************/
/* クラスCustomerの定義 */
/************************/
class Customer
{
	double time;   // 到着時刻
	int state1;   // 客の状態1
                 //   =0 : 待ち行列に入っている
                 //   =1 : サービスを受けている
	int state2;   // 客の状態2(待ち行列番号,または,窓口番号)

	/*********************/
	/* コンストラクタ    */
	/*      s1,s2 : 状態 */
	/*      t : 到着時刻 */
	/*******************************/
	Customer(int s1, int s2, double t)
	{
		time   = t;
		state1 = s1;
		state2 = s2;
	}
}

/**********************/
/* クラスQ_baseの定義 */
/**********************/
class Q_base {
	private String name;            // システム名
	private double p_time;            // 現在時刻
	private int max_c;              // 最大系内客数
	private int nc;                 // 到着客数カウンタ
	private double now_c_t;         // 現在の系内客数になった時間
	private double c_now_c;         // 系内客数にその数が継続した時間を乗じた値の累計
	private double c_sys;           // 滞在時間の累計
	private double max_sys;         // 最大滞在時間
	private double end;             // シミュレーション終了時間
	private Random rn;              // 乱数
	private TreeMap <Integer, Customer> cus;   // 系内にいる客のリスト
	private ArrayList <Inlet> inl;   // Inletオブジェクトリスト
	private ArrayList <Queue> que;   // Queueオブジェクトリスト
	private ArrayList <Entity> ent;   // Entityオブジェクトリスト

	/***************************************/
	/* コンストラクタ                      */
	/*      v_i : Inletオブジェクトリスト  */
	/*      v_q : Queueオブジェクトリスト  */
	/*      v_e : Entityオブジェクトリスト */
	/*      e : シミュレーション終了時刻   */
	/***************************************/
	Q_base(ArrayList<Inlet> v_i, ArrayList<Queue> v_q, ArrayList<Entity> v_e, double e)
	{
					// 接続関係のチェック
		System.out.println();
							// Inlet
		inl = v_i;
		que = v_q;
		ent = v_e;
		for (int i1 = 0; i1 < inl.size()-1; i1++) {
			for (int i2 = i1+1; i2 < inl.size(); i2++) {
				if (inl.get(i1).name.equals(inl.get(i2).name)) {
					System.out.println("***error 同じ名前の入り口があります " + inl.get(i1).name);
					System.exit(1);
				}
			}
		}

		int k;
		for (int i1 = 0; i1 < inl.size(); i1++) {
			k = -1;
			for (int i2 = 0; i2 < que.size(); i2++) {
				if (inl.get(i1).out.equals(que.get(i2).name)) {
					k = i2;
					break;
				}
			}
			if (k >= 0)
				inl.get(i1).out_n = k;
			else {
				System.out.println("***error 入り口から入る待ち行列名が不適当です " + inl.get(i1).out);
				System.exit(1);
			}
		}
							// Queue
		for (int i1 = 0; i1 < que.size()-1; i1++) {
			for (int i2 = i1+1; i2 < que.size(); i2++) {
				if (que.get(i1).name.equals(que.get(i2).name)) {
					System.out.println("***error 同じ名前の待ち行列があります " + que.get(i1).name);
					System.exit(1);
				}
			}
		}

		for (int i1 = 0; i1 < que.size(); i1++) {
			if (que.get(i1).n == 0) {
				k = -1;
				for (int i2 = 0; i2 < inl.size(); i2++) {
					if (que.get(i1).in.get(0).equals(inl.get(i2).name)) {
						k = i2;
						break;
					}
				}
				if (k >= 0)
					que.get(i1).in_n.add(new Integer(k));
				else {
					System.out.println("***error 待ち行列に入る入り口名が不適当です " + que.get(i1).in.get(0));
					System.exit(1);
				}
			}
			else {
				for (int i2 = 0; i2 < que.get(i1).n; i2++) {
					k = -1;
					for (int i3 = 0; i3 < ent.size(); i3++) {
						if (que.get(i1).in.get(i2).equals(ent.get(i3).name)) {
							k = i3;
							break;
						}
					}
					if (k >= 0)
						que.get(i1).in_n.add(new Integer(k));
					else {
						System.out.println("***error 待ち行列に入る窓口名が不適当です " + que.get(i1).in.get(i2));
						System.exit(1);
					}
				}
			}
			for (int i2 = 0; i2 < que.get(i1).m; i2++) {
				k = -1;
				for (int i3 = 0; i3 < ent.size(); i3++) {
					if (que.get(i1).out.get(i2).equals(ent.get(i3).name)) {
						k = i3;
						break;
					}
				}
				if (k >= 0)
					que.get(i1).out_n.add(new Integer(k));
				else {
					System.out.println("***error 待ち行列を処理する窓口名が不適当です " + que.get(i1).out.get(i2));
					System.exit(1);
				}
			}
		}
							// Entity
		for (int i1 = 0; i1 < ent.size()-1; i1++) {
			k = -1;
			for (int i2 = i1+1; i2 < ent.size(); i2++) {
				if (ent.get(i1).name.equals(ent.get(i2).name)) {
					System.out.println("***error 同じ名前の窓口があります " + ent.get(i1).name);
					System.exit(1);
				}
			}
		}

		for (int i1 = 0; i1 < ent.size(); i1++) {
			k = -1;
			for (int i2 = 0; i2 < que.size(); i2++) {
				if (ent.get(i1).in.equals(que.get(i2).name)) {
					k = i2;
					break;
				}
			}
			if (k >= 0)
				ent.get(i1).in_n = k;
			else {
				System.out.println("***error 窓口に入る待ち行列名が不適当です " + ent.get(i1).in);
				System.exit(1);
			}
			if (ent.get(i1).to > 0) {
				k = -1;
				for (int i2 = 0; i2 < que.size(); i2++) {
					if (ent.get(i1).out.equals(que.get(i2).name)) {
						k = i2;
						break;
					}
				}
				if (k >= 0)
					ent.get(i1).out_n = k;
				else {
					System.out.println("***error 窓口の出口にある待ち行列名が不適当です " + ent.get(i1).out);
					System.exit(1);
				}
			}
		}
					// 初期設定
		cus     = new TreeMap <Integer, Customer>();
		p_time  = 0.0;
		max_c   = 0;
		nc      = 0;
		now_c_t = 0.0;
		c_now_c = 0.0;
		c_sys   = 0.0;
		max_sys = 0.0;
		end     = e;
					// 乱数の初期設定
		rn = new Random();
	}

	/**********************/
	/* 指数分布乱数の発生 */
	/*      m : 平均値    */
	/*      rerutn : 乱数 */
	/**********************/
	double Exp_b(double m)
	{
		return -m * Math.log(rn.nextDouble());
	}

	/**************/
	/* 全体の制御 */
	/**************/
	void Control()
	{
					// 到着時間の初期設定
		for (int i1 = 0; i1 < inl.size(); i1++) {
			if (inl.get(i1).a_t == 0)
				inl.get(i1).arrive_time = Exp_b(inl.get(i1).mean);
		}
					// 実行制御
		int sw[] = new int [2];
		sw[0] = 0;
		while (sw[0] > -2) {
			Next(sw);   // 次の処理の選択
			if (sw[0] == -1)
				sw[0] = End_o_s();   // シミュレーションの終了
			else {
				if (sw[0] == 0)
					Arrive(sw[1]);   // 客の到着処理
				else
					Service(sw[1]);   // サービスの終了
			}
		}
	}

	/*********************************************/
	/* 次の処理の決定                            */
	/*      sw[0] : =-1 : シミュレーションの終了 */
	/*              =0  : 客の到着処理           */
	/*              =1  : 窓口のサービス終了     */
	/*        [1] : 入り口番号 or 窓口番号       */
	/*********************************************/
	void Next(int sw[])
	{
		double tm = end;   // 次の処理時刻
		sw[0] = -1;
					// 次の客の到着時刻
		for (int i1 = 0; i1 < inl.size(); i1++) {
			Inlet x = inl.get(i1);
			if (x.arrive_time >= 0.0 && x.arrive_time < tm) {
				sw[0] = 0;
				sw[1] = i1;
				tm    = x.arrive_time;
			}
		}
					// サービス終了時刻
		for (int i1 = 0; i1 < ent.size(); i1++) {
			Entity x = ent.get(i1);
			if (x.service > 0 && x.end_time <= tm) {
				sw[0] = 1;
				sw[1] = i1;
				tm    = x.end_time;
			}
		}

		if (sw[0] < 0)
			end = p_time;
	}

	/**********************************/
	/* 終了処理                       */
	/*      return : =-1 : 終了前処理 */
	/*               =-2 : 実際の終了 */
	/**********************************/
	int End_o_s()
	{
		int sw = -2;
		p_time = end;   // 現在時刻

		for (int i1 = 0; i1 < ent.size(); i1++) {
			Entity x = ent.get(i1);
			if (x.service > 0) {   // サービス中の客はいるか?
				if (sw == -2) {
					sw  = -1;
					end = x.end_time;   // 窓口i1のサービス終了時刻
				}
				else {
					if (x.end_time > end)
						end = x.end_time;   // 窓口i1のサービス終了時刻
				}
			}
		}

		return sw;
	}

	/************************/
	/* 客の到着処理         */
	/*      kk : 入り口番号 */
	/************************/
	void Arrive(int kk)
	{
	/*
	          客数の増加と次の客の到着時刻の設定
	*/
		nc     += 1;   // 到着客数カウンタ
		p_time  = inl.get(kk).arrive_time;   // 現在時刻
		if (inl.get(kk).a_t == 0)   // 次の客の到着時刻
			inl.get(kk).arrive_time = p_time + Exp_b(inl.get(kk).mean);
		else if (inl.get(kk).a_t == 1)
			inl.get(kk).arrive_time = p_time + inl.get(kk).mean;
		else {
			if (inl.get(kk).que.isEmpty())
				inl.get(kk).arrive_time = -1.0;
			else
				inl.get(kk).arrive_time = inl.get(kk).que.pollFirst().doubleValue();
		}
		if (inl.get(kk).arrive_time >= end)
			inl.get(kk).arrive_time = -1.0;
	/*
	          系内客数の処理
	*/
		c_now_c += cus.size() * (p_time - now_c_t);   // 系内客数にその数が継続した時間を乗じた値の累計
		now_c_t  = p_time;   // 現在の系内客数になった時刻
		if ((int)cus.size()+1 > max_c)
			max_c = cus.size() + 1;   // 最大系内客数
	/*
	          空いている窓口を探す
	*/
		int k1 = inl.get(kk).out_n;
		que.get(k1).nc++;
		int k = -1;
		for (int i1 = 0; i1 < que.get(k1).m; i1++) {
			int k2 = que.get(k1).out_n.get(i1);   // 処理窓口
			if (ent.get(k2).service == 0) {
				k = k2;
				break;
			}
		}
	/*
	          窓口に空きがない場合
	*/
		if (k < 0) {
			Customer ct_p = new Customer(0, k1, p_time);
			cus.put(new Integer(nc), ct_p);   // 客の登録(系内客数)
			que.get(k1).c_ql += que.get(k1).que.size() * (p_time - que.get(k1).ql_t);   // 待ち行列長にその長さが継続した時間を乗じた値の累計
			que.get(k1).que.add(new Integer(nc));   // 客の登録(待ち行列)
			que.get(k1).ql_t = p_time;   // 現在の待ち行列長になった時刻
			if (que.get(k1).que.size() > que.get(k1).max_q_l)
				que.get(k1).max_q_l = que.get(k1).que.size();   // 最大待ち行列長
		}
	/*
	          すぐサービスをうけられる場合
	*/
		else {
			Customer ct_p = new Customer(1, k, p_time);
			cus.put(new Integer(nc), ct_p);   // 客の登録(系内客数)
			ent.get(k).service = nc;   // サービスを受けている客番号
			ent.get(k).busy_t  = p_time;   // 窓口がふさがった時刻
			if (ent.get(k).s_t == 0)   // 窓口のサービス終了時刻
				ent.get(k).end_time = p_time + Exp_b(ent.get(k).mean);
			else
				ent.get(k).end_time = p_time + ent.get(k).mean;
		}
	}

	/**********************************/
	/* サービス終了時の処理           */
	/*      kk : サービス終了窓口番号 */
	/**********************************/
	void Service(int kk)
	{
	/*
	          時間の設定
	*/
		p_time = ent.get(kk).end_time;   // 現在時刻
		ent.get(kk).end_time = -1.0;   // サービス終了時間
	/*
	          システムの外へ出る場合
	*/
		if (ent.get(kk).to == 0) {
	/*
	               系内客数の処理
	*/
			c_now_c += cus.size() * (p_time - now_c_t);   // 系内客数にその数が継続した時間を乗じた値の累計
			now_c_t  = p_time;   // 現在の系内客数になった時刻
	/*
	               滞在時間の処理
	*/
			Customer it = cus.get(new Integer(ent.get(kk).service));   // サービス中の客
			double x1 = p_time - it.time;
			c_sys += x1;   // 滞在時間の累計
			if (x1 > max_sys)
				max_sys = x1;   // 最大滞在時間
			cus.remove(new Integer(ent.get(kk).service));   // 客の削除(系内客数)
		}
	/*
	          他の窓口処理へ入る場合の処理
	*/
		else {
			int k1 = ent.get(kk).out_n;
			que.get(k1).nc++;
			int sw = 1;
			int k2 = 0;
			if (que.get(k1).que.size() == 0) {
				for (int i1 = 0; i1 < que.get(k1).m; i1++) {
					k2 = que.get(k1).out_n.get(i1);   // 窓口
					if (ent.get(k2).service == 0) {
						sw = 0;
						break;
					}
				}
			}
	/*
	               待ち行列がある場合
	*/
			if (sw > 0) {
				que.get(k1).c_ql += que.get(k1).que.size() * (p_time - que.get(k1).ql_t);   // 待ち行列長にその長さが継続した時間を乗じた値の累計
				que.get(k1).que.add(new Integer(ent.get(kk).service));   // 客の登録(待ち行列)
				que.get(k1).ql_t = p_time;   // 現在の待ち行列長になった時刻
				if (que.get(k1).que.size() > que.get(k1).max_q_l)
					que.get(k1).max_q_l = que.get(k1).que.size();   // 最大待ち行列長
				Customer it = cus.get(new Integer(ent.get(kk).service));
				it.state1 = 0;   // 客の状態変更(待ち行列)
				it.state2 = ent.get(kk).out_n;   // 客の状態変更(待ち行列番号)
			}
	/*
	               すぐサービスをうけられる場合
	*/
			else {
				ent.get(k2).service = ent.get(kk).service;   // サービスを受けている客番号
				ent.get(k2).busy_t  = p_time;   // 窓口がふさがった時刻
				if (ent.get(k2).s_t == 0)   // 窓口のサービス終了時刻
					ent.get(k2).end_time = p_time + Exp_b(ent.get(k2).mean);
				else
					ent.get(k2).end_time = p_time + ent.get(k2).mean;
			}
		}
	/*
	          窓口使用時間の処理
	*/
		ent.get(kk).service  = 0;   // 窓口を空き状態にする
		ent.get(kk).c_busy  += (p_time - ent.get(kk).busy_t);   // 窓口がふさがっている時間の累計
	/*
	          この窓口に対する待ち行列がある場合
	*/
		int k3 = ent.get(kk).in_n;
		if (que.get(k3).que.size() > 0) {
			que.get(k3).c_ql += que.get(k3).que.size() * (p_time - que.get(k3).ql_t);   // 待ち行列長にその長さが継続した時間を乗じた値の累計
			int n = que.get(k3).que.pollFirst().intValue();   // 待ち行列の先頭にいる客の削除
			que.get(k3).ql_t = p_time;   // 現在の待ち行列長になった時刻
			Customer it = cus.get(new Integer(n));
			double x1 = p_time - it.time;
			que.get(k3).c_wt += x1;   // 待ち時間の累計
			if (x1 > que.get(k3).max_wt)
				que.get(k3).max_wt = x1;   // 最大待ち時間
			for (int i1 = 0; i1 < que.get(k3).m; i1++) {
				int k4 = que.get(k3).out_n.get(i1);   // 窓口
				if (ent.get(k4).service == 0) {
					ent.get(k4).service = n;   // 窓口の客番号
					ent.get(k4).busy_t  = p_time;   // 窓口がふさがった時刻
					if (ent.get(k4).s_t == 0)   // 窓口のサービス終了時刻
						ent.get(k4).end_time = p_time + Exp_b(ent.get(k4).mean);
					else
						ent.get(k4).end_time = p_time + ent.get(k4).mean;
					it.state1 = 1;   // 客の状態変更(サービス中)
					it.state2 = k4;   // 客の状態変更(窓口番号)
					break;
				}
			}
		}
	}

	/**************************/
	/* 統計量の計算と最終出力 */
	/**************************/
	void Output()
	{
					// System
		System.out.printf("全客数 %d", nc);
		System.out.printf(" 最大系内客数 %d 最大滞在時間 %.3f\n", max_c, max_sys);
		System.out.printf("   平均系内客数 %.3f", c_now_c / p_time);
		System.out.printf(" 平均滞在時間 %.3f", c_sys / nc);
		System.out.printf(" 終了時間 %.3f\n", p_time);
					// Entity
		for (int i1 = 0; i1 < ent.size(); i1++) {
			Entity e = ent.get(i1);
			System.out.printf("Entity %s 稼働率 %.3f\n", e.name, e.c_busy / p_time);
		}
					// Queue
		for (int i1 = 0; i1 < que.size(); i1++) {
			Queue q = que.get(i1);
			System.out.printf("Queue %s 客数 %d", q.name, q.nc);
			System.out.printf("   最大待ち行列長 %d", q.max_q_l);
			System.out.printf("   最大待ち時間 %.3f\n", q.max_wt);
			System.out.printf("      平均待ち行列長 %.3f", q.c_ql / p_time);
			System.out.printf("   平均待ち時間 %.3f\n", q.c_wt / q.nc);
		}
	}
}

/*
------------入力例(簡単な場合)-----------
1
  Inlet
    0
    5
    Queue
1
  Queue
    0
      Inlet
    2
      Entity1
      Entity2
2
  Entity1
    0
      4
    Queue
      0
  Entity2
    0
      4
    Queue
      0
10000

------------入力例(複雑な場合)-----------
2
  Inlet1
    0
      5
    Queue1
  Inlet2
    0
      5
    Queue2
3
  Queue1
    0
      Inlet1
    1
      Entity1
  Queue2
    0
      Inlet2
    1
      Entity2
  Queue3
    2
      Entity1
      Entity2
    2
      Entity3
      Entity4
4
  Entity1
    0
      4
    Queue1
      1
        Queue3
  Entity2
    0
      4
    Queue2
      1
        Queue3
  Entity3
    0
      3
    Queue3
      0
  Entity4
    0
      3
    Queue3
      0
10000
*/