静岡理工科大学 菅沼ホーム 目次 索引

待ち行列(複雑な例)

    1. A. C++
    2. B. Java
    3. C. JavaScript
    4. D. PHP
    5. E. Ruby
    6. F. Python
    7. G. C#
    8. H. VB

  プログラムは,先の例(簡単な例)より複雑な待ち行列モデル

をシミュレーションするためのものです.入力データによって,様々な構造のモデルに対するシミュレーションも可能です.また,到着時間に関しては,(指数分布,一定時間間隔,客の人数と到着時間の指定)の中から,また,サービス時間に関しては,(指数分布,一定時間)の中から選択可能です.プログラムの最後に,上の図に示したモデルをシミュレーションするための入力例,及び,先の例(簡単な例)に対する入力例が与えてあります.必要のない入力促進文字が出力されますが,これらのデータをファイルに保存し,リダイレクトを行うことによっても実行可能です.なお,このプログラムでは,クラスを使用しています.

  1. C++

      C++11 においては,「メルセンヌ・ツイスター法による擬似乱数生成エンジン」を使用することができます.
    /******************************/
    /* 複雑な待ち行列問題         */
    /*      coded by Y.Suganuma   */
    /******************************/
    #include <stdio.h>
    #include <iostream>
    #include <stdlib.h>
    #include <math.h>
    #include <ctime>
    #include <map>
    #include <queue>
    #include <vector>
    #include <string>
    #include "MT.h"
    using namespace std;
    
    /**********************/
    /* 指数分布乱数の発生 */
    /*      m : 平均値    */
    /*      rerutn : 乱数 */
    /**********************/
    double Exp_b(double m)
    {
    	return -m * log(genrand_real3());
    }
    
    /*********************/
    /* クラスInletの定義 */
    /*********************/
    class Inlet {
    		string name;   // 入り口名
    		string out;   // 待ち行列名
    		int out_n;   // 待ち行列番号
    		double arrive_time;   // 客の到着時刻(負:客がない)
    		int a_t;   // = -n : 到着する客の人数を負の値にしたもの
    		           // =0 : 指数分布
    		           // =1 : 一定時間間隔
    		double mean;   // 到着時間間隔またはその平均
    		queue<double> que;   // 客の到着時刻リスト
    	public:
    		/*************************************************************/
    		/* コンストラクタ                                            */
    		/*      name1 : 入り口名                                     */
    		/*      a_t1;   // = -n : 到着する客の人数を負の値にしたもの */
    		/*              // =0 : 指数分布                             */
    		/*              // =1 : 一定時間間隔                         */
    		/*      m_a: 到着時間間隔またはその平均                     */
    		/*      que1 : 客の到着時刻リスト                            */
    		/*      name2 : 待ち行列名                                   */
    		/*************************************************************/
    		Inlet (string name1, int a_t1, double m_a, queue<double> que1, string name2)
    		{
    			name = name1;
    			out  = name2;
    			a_t  = a_t1;
    			mean = m_a;
    			que  = que1;
    			if (a_t == 0)
    				arrive_time = Exp_b(mean);
    			else if (a_t == 1)
    				arrive_time = 0;
    			else {
    				arrive_time = que.front();
    				que.pop();
    			}
    		}
    	friend class Q_base;
    };
    
    /*********************/
    /* クラス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 : 複数の窓口から入る(窓口数)
    		vector<string> in;   // 入り口名,または,窓口名
    		vector<int> in_n;   // 入り口番号,または,窓口番号
    		int m;   // 処理する窓口数
    		vector<string> out;   // 窓口名
    		vector<int> out_n;   // 窓口番号
    		queue<int> que;   // 待ち行列
    	public:
    		/*********************************************/
    		/* コンストラクタ                            */
    		/*      name1 : 待ち行列名                   */
    		/*      n1 : =0 : 入り口から入る             */
    		/*           >0 : 複数の窓口から入る(窓口数) */
    		/*      in1 : 入り口名,または,窓口名       */
    		/*      m1 : 処理する窓口数                  */
    		/*      out1 : 窓口名                        */
    		/*********************************************/
    		Queue(string name1, int n1, vector<string> in1, int m1, vector<string> out1)
    		{
    			name    = name1;
    			n       = n1;
    			in      = in1;
    			m       = m1;
    			out     = out1;
    			nc      = 0;
    			max_q_l = 0;
    			c_ql    = 0.0;
    			ql_t    = 0.0;
    			max_wt  = 0.0;
    			c_wt    = 0.0;
    		}
    	friend class Q_base;
    };
    
    /**********************/
    /* クラスEntityの定義 */
    /**********************/
    class Entity {
    		string name;   // 窓口名
    		double end_time;   // サービス終了時刻(負:何も処理していない)
    		int s_t;   // =0 : 指数分布
    		           // =1 : 一定時間
    		double mean;   // 平均サービス時間
    		double busy_t;   // 窓口がふさがった時刻
    		double c_busy;   // 窓口がふさがっている時間の累計
    		int service;   // サービス中の客番号(0のときは無し)
    		string in;   // 待ち行列(入力)の名前
    		int in_n;   // 待ち行列(入力)番号
    		int to;   // =0 : システムの外に出る
    		          // =1 : 待ち行列に入る
    		string out;   // 待ち行列(出力)の名前
    		int out_n;   // 待ち行列(出力)番号
    	public:
    		/****************************************/
    		/* コンストラクタ                       */
    		/*      name1 : 窓口名                  */
    		/*      s_t1;   // =0 : 指数分布        */
    		/*              // =1 : 一定時間        */
    		/*      m_s:サービス時間またはその平均 */
    		/*      name2 : 待ち行列(入力)の名前    */
    		/*      sw : =0 : システムの外に出る    */
    		/*           =1 : 待ち行列に入る        */
    		/*      name3 : 待ち行列(出力)の名前    */
    		/**********************************+++***/
    		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;
    		}
    	friend class Q_base;
    };
    
    /************************/
    /* クラスCustomerの定義 */
    /************************/
    class Customer
    {
    	public :
    		double time;   // 到着時刻
    		int state1;   // 客の状態1
                         //   =0 : 待ち行列に入っている
                         //   =1 : サービスを受けている
    		int state2;   // 客の状態2(待ち行列番号,または,窓口番号)
    		/*********************/
    		/* コンストラクタ    */
    		/*      s1,s2 : 状態 */
    		/*      t : 到着時刻 */
    		/*******************************/
    		Customer::Customer(int s1, int s2, double t)
    		{
    			time   = t;
    			state1 = s1;
    			state2 = s2;
    		}
    };
    
    /**********************/
    /* クラスQ_baseの定義 */
    /**********************/
    class Q_base {
    		double p_time;  // 現在時刻
    		int max_c;   // 最大系内客数
    		int nc;   // システムへの到着客数カウンタ
    		double now_c_t;   // 現在の系内客数になった時間
    		double c_now_c;   // 系内客数にその数が継続した時間を乗じた値の累計
    		double c_sys;   // 滞在時間の累計
    		double max_sys;   // 最大滞在時間
    		double end;   // シミュレーション終了時間
    		map<int, Customer> cus;   // 系内にいる客のリスト
    		vector<Inlet> inl;   // Inletオブジェクトリスト
    		vector<Queue> que;   // Queueオブジェクトリスト
    		vector<Entity> ent;   // Entityオブジェクトリスト
    	public:
    		/***************************************/
    		/* コンストラクタ                      */
    		/*      v_i : Inletオブジェクトリスト  */
    		/*      v_q : Queueオブジェクトリスト  */
    		/*      v_e : Entityオブジェクトリスト */
    		/*      e : シミュレーション終了時刻   */
    		/***************************************/
    		Q_base(vector<Inlet> v_i, vector<Queue> v_q, vector<Entity> v_e, double e)
    		{
    					// 接続関係のチェック
    			cout << "\n";
    							// Inlet
    			inl = v_i;
    			que = v_q;
    			ent = v_e;
    			for (int i1 = 0; i1 < (int)inl.size()-1; i1++) {
    				for (int i2 = i1+1; i2 < (int)inl.size(); i2++) {
    					if (inl[i1].name == inl[i2].name) {
    						cout << "***error 同じ名前の入り口があります " + inl[i1].name + "\n";
    						exit(1);
    					}
    				}
    			}
    
    			int k;
    			for (int i1 = 0; i1 < (int)inl.size(); i1++) {
    				k = -1;
    				for (int i2 = 0; i2 < (int)que.size(); i2++) {
    					if (inl[i1].out == que[i2].name) {
    						k = i2;
    						break;
    					}
    				}
    				if (k >= 0)
    					inl[i1].out_n = k;
    				else {
    					cout << "***error 入り口から入る待ち行列名が不適当です " + inl[i1].out + "\n";
    					exit(1);
    				}
    			}
    							// Queue
    			for (int i1 = 0; i1 < (int)que.size()-1; i1++) {
    				for (int i2 = i1+1; i2 < (int)que.size(); i2++) {
    					if (que[i1].name == que[i2].name) {
    						cout << "***error 同じ名前の待ち行列があります " + que[i1].name + "\n";
    						exit(1);
    					}
    				}
    			}
    
    			for (int i1 = 0; i1 < (int)que.size(); i1++) {
    				if (que[i1].n == 0) {
    					k = -1;
    					for (int i2 = 0; i2 < (int)inl.size(); i2++) {
    						if (que[i1].in[0] == inl[i2].name) {
    							k = i2;
    							break;
    						}
    					}
    					if (k >= 0)
    						que[i1].in_n.push_back(k);
    					else {
    						cout << "***error 待ち行列に入る入り口名が不適当です " + que[i1].in[0] + "\n";
    						exit(1);
    					}
    				}
    				else {
    					for (int i2 = 0; i2 < (int)que[i1].n; i2++) {
    						k = -1;
    						for (int i3 = 0; i3 < (int)ent.size(); i3++) {
    							if (que[i1].in[i2] == ent[i3].name) {
    								k = i3;
    								break;
    							}
    						}
    						if (k >= 0)
    							que[i1].in_n.push_back(k);
    						else {
    							cout << "***error 待ち行列に入る窓口名が不適当です " + que[i1].in[i2] + "\n";
    							exit(1);
    						}
    					}
    				}
    				for (int i2 = 0; i2 < (int)que[i1].m; i2++) {
    					k = -1;
    					for (int i3 = 0; i3 < (int)ent.size(); i3++) {
    						if (que[i1].out[i2] == ent[i3].name) {
    							k = i3;
    							break;
    						}
    					}
    					if (k >= 0)
    						que[i1].out_n.push_back(k);
    					else {
    						cout << "***error 待ち行列を処理する窓口名が不適当です " + que[i1].out[i2] + "\n";
    						exit(1);
    					}
    				}
    			}
    							// Entity
    			for (int i1 = 0; i1 < (int)ent.size()-1; i1++) {
    				k = -1;
    				for (int i2 = i1+1; i2 < (int)ent.size(); i2++) {
    					if (ent[i1].name == ent[i2].name) {
    						cout << "***error 同じ名前の窓口があります " + ent[i1].name + "\n";
    						exit(1);
    					}
    				}
    			}
    
    			for (int i1 = 0; i1 < (int)ent.size(); i1++) {
    				k = -1;
    				for (int i2 = 0; i2 < (int)que.size(); i2++) {
    					if (ent[i1].in == que[i2].name) {
    						k = i2;
    						break;
    					}
    				}
    				if (k >= 0)
    					ent[i1].in_n = k;
    				else {
    					cout << "***error 窓口に入る待ち行列名が不適当です " + ent[i1].in + "\n";
    					exit(1);
    				}
    				if (ent[i1].to > 0) {
    					k = -1;
    					for (int i2 = 0; i2 < (int)que.size(); i2++) {
    						if (ent[i1].out == que[i2].name) {
    							k = i2;
    							break;
    						}
    					}
    					if (k >= 0)
    						ent[i1].out_n = k;
    					else {
    						cout << "***error 窓口の出口にある待ち行列名が不適当です " + ent[i1].out + "\n";
    						exit(1);
    					}
    				}
    			}
    					// 初期設定
    			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;
    					// 乱数の初期設定
    			init_genrand((unsigned)time(NULL));
    		}
    		void Control();   // 全体の制御
    		void Next(int *);   // 次の処理の決定
    		int End_o_s();   // 終了処理
    		void Arrive(int);   // 客の到着
    		void Service(int);   // サービス終了
    		void Output();   // 結果の出力
    };
    
    /**************/
    /* 全体の制御 */
    /**************/
    void Q_base::Control()
    {
    	int sw[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 Q_base::Next(int *sw)
    {
    	double tm = end;   // 次の処理時刻
    	sw[0] = -1;
    					// 次の客の到着時刻
    	for (int i1 = 0; i1 < (int)inl.size(); i1++) {
    		Inlet x = inl[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 < (int)ent.size(); i1++) {
    		Entity x = ent[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 Q_base::End_o_s()
    {
    	int sw = -2;
    	p_time = end;   // 現在時刻
    
    	for (int i1 = 0; i1 < (int)ent.size(); i1++) {
    		Entity x = ent[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 Q_base::Arrive(int kk)
    {
    /*
              客数の増加と次の客の到着時刻の設定
    */
    	nc      += 1;   // 到着客数カウンタ
    	p_time  = inl[kk].arrive_time;   // 現在時刻
    	if (inl[kk].a_t == 0)   // 次の客の到着時刻
    		inl[kk].arrive_time = p_time + Exp_b(inl[kk].mean);   
    	else if (inl[kk].a_t == 1)
    		inl[kk].arrive_time = p_time + inl[kk].mean;   
    	else {
    		if (inl[kk].que.empty())
    			inl[kk].arrive_time = -1.0;
    		else {
    			inl[kk].arrive_time = inl[kk].que.front();
    			inl[kk].que.pop();
    		}
    	}
    	if (inl[kk].arrive_time >= end)
    		inl[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[kk].out_n;
    	que[k1].nc++;
    	int k = -1;
    	for (int i1 = 0; i1 < que[k1].m; i1++) {
    		int k2 = que[k1].out_n[i1];   // 処理窓口
    		if (ent[k2].service == 0) {
    			k = k2;
    			break;
    		}
    	}
    /*
              窓口に空きがない場合
    */
    	if (k < 0) {
    		Customer ct_p(0, k1, p_time);
    		cus.insert(pair<int, Customer>(nc, ct_p));   // 客の登録(系内客数)
    		que[k1].c_ql += que[k1].que.size() * (p_time - que[k1].ql_t);   // 待ち行列長にその長さが継続した時間を乗じた値の累計
    		que[k1].que.push(nc);   // 客の登録(待ち行列)
    		que[k1].ql_t = p_time;   // 現在の待ち行列長になった時刻
    		if ((int)que[k1].que.size() > que[k1].max_q_l)
    			que[k1].max_q_l = que[k1].que.size();   // 最大待ち行列長
    	}
    /*
              すぐサービスをうけられる場合
    */
    	else {
    		Customer ct_p(1, k, p_time);
    		cus.insert(pair<int, Customer>(nc, ct_p));   // 客の登録(系内客数)
    		ent[k].service = nc;   // サービスを受けている客番号
    		ent[k].busy_t  = p_time;   // 窓口がふさがった時刻
    		if (ent[k].s_t == 0)   // 窓口のサービス終了時刻
    			ent[k].end_time = p_time + Exp_b(ent[k].mean);
    		else
    			ent[k].end_time = p_time + ent[k].mean;
    	}
    }
    
    /**********************************/
    /* サービス終了時の処理           */
    /*      kk : サービス終了窓口番号 */
    /**********************************/
    void Q_base::Service(int kk)
    {
    	map<int, Customer>::iterator it;
    /*
              時間の設定
    */
    	p_time = ent[kk].end_time;   // 現在時刻
    	ent[kk].end_time = -1.0;   // サービス終了時間
    /*
              システムの外へ出る場合
    */
    	if (ent[kk].to == 0) {
    /*
                   系内客数の処理
    */
    		c_now_c += cus.size() * (p_time - now_c_t);   // 系内客数にその数が継続した時間を乗じた値の累計
    		now_c_t  = p_time;   // 現在の系内客数になった時刻
    /*
                   滞在時間の処理
    */
    		it = cus.find(ent[kk].service);   // サービス中の客
    		double x1 = p_time - (it->second).time;
    		c_sys += x1;   // 滞在時間の累計
    		if (x1 > max_sys)
    			max_sys = x1;   // 最大滞在時間
    		cus.erase(ent[kk].service);   // 客の削除(系内客数)
    	}
    /*
              他の窓口処理へ入る場合の処理
    */
    	else {
    		int k1 = ent[kk].out_n;
    		que[k1].nc++;
    		int sw = 1;
    		int k2 = 0;
    		if (que[k1].que.size() == 0) {
    			for (int i1 = 0; i1 < que[k1].m; i1++) {
    				k2 = que[k1].out_n[i1];   // 窓口
    				if (ent[k2].service == 0) {
    					sw = 0;
    					break;
    				}
    			}
    		}
    /*
                   待ち行列がある場合
    */
    		if (sw > 0) {
    			que[k1].c_ql += que[k1].que.size() * (p_time - que[k1].ql_t);   // 待ち行列長にその長さが継続した時間を乗じた値の累計
    			que[k1].que.push(ent[kk].service);   // 客の登録(待ち行列)
    			que[k1].ql_t = p_time;   // 現在の待ち行列長になった時刻
    			if ((int)que[k1].que.size() > que[k1].max_q_l)
    				que[k1].max_q_l = que[k1].que.size();   // 最大待ち行列長
    			it = cus.find(ent[kk].service);
    			(it->second).state1 = 0;   // 客の状態変更(待ち行列)
    			(it->second).state2 = ent[kk].out_n;   // 客の状態変更(待ち行列番号)
    		}
    /*
                   すぐサービスをうけられる場合
    */
    		else {
    			ent[k2].service = ent[kk].service;   // サービスを受けている客番号
    			ent[k2].busy_t  = p_time;   // 窓口がふさがった時刻
    			if (ent[k2].s_t == 0)   // 窓口のサービス終了時刻
    				ent[k2].end_time = p_time + Exp_b(ent[k2].mean);
    			else
    				ent[k2].end_time = p_time + ent[k2].mean;
    		}
    	}
    /*
              窓口使用時間の処理
    */
    	ent[kk].service  = 0;   // 窓口を空き状態にする
    	ent[kk].c_busy  += (p_time - ent[kk].busy_t);   // 窓口がふさがっている時間の累計
    /*
              この窓口に対する待ち行列がある場合
    */
    	int k3 = ent[kk].in_n;
    	if (que[k3].que.size() > 0) {
    		que[k3].c_ql += que[k3].que.size() * (p_time - que[k3].ql_t);   // 待ち行列長にその長さが継続した時間を乗じた値の累計
    		int n = que[k3].que.front();   // 待ち行列の先頭にいる客
    		que[k3].que.pop();   // 客の削除(待ち行列)
    		que[k3].ql_t = p_time;   // 現在の待ち行列長になった時刻
    		it = cus.find(n);
    		double x1 = p_time - (it->second).time;
    		que[k3].c_wt += x1;   // 待ち時間の累計
    		if (x1 > que[k3].max_wt)
    			que[k3].max_wt = x1;   // 最大待ち時間
    		for (int i1 = 0; i1 < que[k3].m; i1++) {
    			int k4 = que[k3].out_n[i1];   // 窓口
    			if (ent[k4].service == 0) {
    				ent[k4].service = n;   // 窓口の客番号
    				ent[k4].busy_t  = p_time;   // 窓口がふさがった時刻
    				if (ent[k4].s_t == 0)   // 窓口のサービス終了時刻
    					ent[k4].end_time = p_time + Exp_b(ent[k4].mean);
    				else
    					ent[k4].end_time = p_time + ent[k4].mean;
    				(it->second).state1 = 1;   // 客の状態変更(サービス中)
    				(it->second).state2 = k4;   // 客の状態変更(窓口番号)
    				break;
    			}
    		}
    	}
    }
    
    /**************************/
    /* 統計量の計算と最終出力 */
    /**************************/
    void Q_base::Output()
    {
    					// System
    	printf("全客数 %d", nc);
    	printf(" 最大系内客数 %d 最大滞在時間 %.3f\n", max_c, max_sys);
    	printf("平均系内客数 %.3f", c_now_c / p_time);
    	printf(" 平均滞在時間 %.3f", c_sys / nc);
    	printf(" 終了時間 %.3f\n", p_time);
    					// Entity
    	for (int i1 = 0; i1 < (int)ent.size(); i1++) {
    		Entity e = ent[i1];
    		cout << "Entity " << e.name;
    		printf(" 稼働率 %.3f\n", e.c_busy / p_time);
    	}
    					// Queue
    	for (int i1 = 0; i1 < (int)que.size(); i1++) {
    		Queue q = que[i1];
    		cout << "Queue " << q.name;
    		printf(" 客数 %d", q.nc);
    		printf("   最大待ち行列長 %d", q.max_q_l);
    		printf("   最大待ち時間 %.3f\n", q.max_wt);
    		printf("      平均待ち行列長 %.3f", q.c_ql / p_time);
    		printf("   平均待ち時間 %.3f\n", q.c_wt / q.nc);
    	}
    }
    
    /****************/
    /* main program */
    /****************/
    int main()
    {
    					// 入り口
    	int n_i;
    	printf("入り口(Inlet)の数は? ");
    	scanf("%d", &n_i);
    	vector<Inlet> inl;
    	for (int i1 = 0; i1 < n_i; i1++) {
    		double m_a;
    		string name1, name2;
    		printf("%d 番目の入り口(Inlet)\n", i1+1);
    		printf("     名前は? ");
    		cin >> name1;
    		int n;
    		queue<double> que;
    		printf("     到着分布(= 0: 指数分布,=1: 一定時間間隔,< 0: 指定,客数の負値)? ");
    		scanf("%d", &n);
    		if (n == 0) {
    			printf("          到着時間間隔の平均値は? ");
    			scanf("%lf", &m_a);
    		}
    		else if (n == 1) {
    			printf("          到着時間間隔は? ");
    			scanf("%lf", &m_a);
    		}
    		else {
    			double x;
    			for (int i2 = 0; i2 < -n; i2++) {
    				printf("          到着時間は? ");
    				scanf("%lf", &x);
    				que.push(x);
    			}
    		}
    		printf("     並ぶ待ち行列の名前は? ");
    		cin >> name2;
    		Inlet inl_e(name1, n, m_a, que, name2);
    		inl.push_back(inl_e);
    	}
    					// 待ち行列
    	int n_q;
    	printf("待ち行列(Queue)の数は? ");
    	scanf("%d", &n_q);
    	vector<Queue> que;
    	for (int i1 = 0; i1 < n_q; i1++) {
    		string name1;
    		printf("%d 番目の待ち行列(Queue)\n", i1+1);
    		printf("     名前は? ");
    		cin >> name1;
    		int n;
    		printf("     入り口(0),または,窓口(n>0,窓口の数)から? ");
    		scanf("%d", &n);
    		vector<string> in;
    		if (n == 0) {
    			string name2;
    			printf("          入り口の名前は? ");
    			cin >> name2;
    			in.push_back(name2);
    		}
    		else {
    			for (int i2 = 0; i2 < n; i2++) {
    				string name3;
    				printf("          %d 番目の窓口の名前は? ", i2+1);
    				cin >> name3;
    				in.push_back(name3);
    			}
    		}
    		int m;
    		printf("     処理する窓口の数は? ");
    		scanf("%d", &m);
    		vector<string> out;
    		for (int i2 = 0; i2 < m; i2++) {
    			string name4;
    			printf("          %d 番目の窓口の名前は? ", i2+1);
    			cin >> name4;
    			out.push_back(name4);
    		}
    		Queue que_e(name1, n, in, m, out);
    		que.push_back(que_e);
    	}
    					// 窓口
    	int n_e;
    	printf("窓口(Entity)の数は? ");
    	scanf("%d", &n_e);
    	vector<Entity> ent;
    	for (int i1 = 0; i1 < n_e; i1++) {
    		double m_s;
    		string name1;
    		printf("%d 番目の窓口(Entity)\n", i1+1);
    		printf("     名前は? ");
    		cin >> name1;
    		int s_t;
    		printf("     サービス分布(=0:指数分布,=1:一定時間)? ");
    		scanf("%d", &s_t);
    		if (s_t == 0) {
    			printf("          サービス時間の平均値は? ");
    			scanf("%lf", &m_s);
    		}
    		else {
    			printf("          サービス時間は? ");
    			scanf("%lf", &m_s);
    		}
    		printf("     待ち行列(入力)の名前は? ");
    		string name2;
    		cin >> name2;
    		int sw;
    		printf("     終了後,外部(0),または,待ち行列(1)? ");
    		scanf("%d", &sw);
    		string name3;
    		if (sw > 0) {
    			printf("          待ち行列(出力)の名前は? ");
    			cin >> name3;
    		}
    		Entity ent_e(name1, s_t, m_s, name2, sw, name3);
    		ent.push_back(ent_e);
    	}
    					// 全体の制御を行うクラス
    	double end;
    	printf("シミュレーション終了時間? ");
    	scanf("%lf", &end);
    
    	Q_base base(inl, que, ent, end);   // 全体の制御を行うクラス
    					// 実行
    	base.Control();
    					// 出力
    	base.Output();
    
    	return 0;
    }
    
    /*
    ------------入力例(簡単な場合)-----------
    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
    
    ------------MT.h-----------
    // Period parameters
    #define MT_N 624
    #define MT_M 397
    #define MATRIX_A 0x9908b0dfUL   // constant vector a
    #define UPPER_MASK 0x80000000UL // most significant w-r bits
    #define LOWER_MASK 0x7fffffffUL // least significant r bits
    
    static unsigned long mt[MT_N]; // the array for the state vector
    static int mti=MT_N+1; // mti==MT_N+1 means mt[MT_N] is not initialized
    
    // initializes mt[MT_N] with a seed
    void init_genrand(unsigned long s)
    {
        mt[0]= s & 0xffffffffUL;
        for (mti=1; mti<MT_N; mti++) {
            mt[mti] = 
    	    (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); 
            // See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
            // In the previous versions, MSBs of the seed affect
            // only MSBs of the array mt[].
            // 2002/01/09 modified by Makoto Matsumoto
            mt[mti] &= 0xffffffffUL;
            // for >32 bit machines
        }
    }
    
    // initialize by an array with array-length
    // init_key is the array for initializing keys
    // key_length is its length
    // slight change for C++, 2004/2/26
    void init_by_array(unsigned long init_key[], int key_length)
    {
        int i, j, k;
        init_genrand(19650218UL);
        i=1; j=0;
        k = (MT_N>key_length ? MT_N : key_length);
        for (; k; k--) {
            mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
              + init_key[j] + j; // non linear
            mt[i] &= 0xffffffffUL; // for WORDSIZE > 32 machines
            i++; j++;
            if (i>=MT_N) { mt[0] = mt[MT_N-1]; i=1; }
            if (j>=key_length) j=0;
        }
        for (k=MT_N-1; k; k--) {
            mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
              - i; // non linear
            mt[i] &= 0xffffffffUL; // for WORDSIZE > 32 machines
            i++;
            if (i>=MT_N) { mt[0] = mt[MT_N-1]; i=1; }
        }
    
        mt[0] = 0x80000000UL; // MSB is 1; assuring non-zero initial array
    }
    
    // generates a random number on [0,0xffffffff]-interval
    unsigned long genrand_int32(void)
    {
        unsigned long y;
        static unsigned long mag01[2]={0x0UL, MATRIX_A};
        // mag01[x] = x * MATRIX_A  for x=0,1
    
        if (mti >= MT_N) { // generate N words at one time
            int kk;
    
            if (mti == MT_N+1)   // if init_genrand() has not been called,
                init_genrand(5489UL); // a default initial seed is used
    
            for (kk=0;kk<MT_N-MT_M;kk++) {
                y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
                mt[kk] = mt[kk+MT_M] ^ (y >> 1) ^ mag01[y & 0x1UL];
            }
            for (;kk<MT_N-1;kk++) {
                y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
                mt[kk] = mt[kk+(MT_M-MT_N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
            }
            y = (mt[MT_N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
            mt[MT_N-1] = mt[MT_M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
    
            mti = 0;
        }
      
        y = mt[mti++];
    
        // Tempering
        y ^= (y >> 11);
        y ^= (y << 7) & 0x9d2c5680UL;
        y ^= (y << 15) & 0xefc60000UL;
        y ^= (y >> 18);
    
        return y;
    }
    
    // generates a random number on [0,0x7fffffff]-interval
    long genrand_int31(void)
    {
        return (long)(genrand_int32()>>1);
    }
    
    // generates a random number on [0,1]-real-interval
    double genrand_real1(void)
    {
        return genrand_int32()*(1.0/4294967295.0); 
        // divided by 2^32-1
    }
    
    // generates a random number on [0,1)-real-interval
    double genrand_real2(void)
    {
        return genrand_int32()*(1.0/4294967296.0); 
        // divided by 2^32
    }
    
    // generates a random number on (0,1)-real-interval
    double genrand_real3(void)
    {
        return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0); 
        // divided by 2^32
    }
    
    // generates a random number on [0,1) with 53-bit resolution
    double genrand_res53(void) 
    { 
        unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; 
        return(a*67108864.0+b)*(1.0/9007199254740992.0); 
    } 
    // These real versions are due to Isaku Wada, 2002/01/09 added
    */
    			

  2. Java

    /******************************/
    /* 複雑な待ち行列問題         */
    /*      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:サービス時間またはその平均 */
    	/*      name2 : 待ち行列(入力)の名前    */
    	/*      sw : =0 : システムの外に出る    */
    	/*           =1 : 待ち行列に入る        */
    	/*      name3 : 待ち行列(出力)の名前    */
    	/****************************************/
    	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
    */
    			

  3. JavaScript

      ここをクリックすると,画面上でシミュレーションを実行し,結果を得ることができます.初期設定の状態は,上の図に示したモデルをシミュレーションするためのものです.入り口,待ち行列,窓口の数などを変えれば(変更して,その位置に対するフォーカスを外せば),対応した状態に対する入力が可能になります.なお,入り口,待ち行列,及び,窓口数の最大値は 10 に設定してありますが,ファイル test.html の対応する箇所を修正することによって,容易に変更可能です.

    test.html

    <!DOCTYPE HTML>
    
    <HTML>
    
    <HEAD>
    
    	<TITLE>複雑な待ち行列</TITLE>
    	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    	<SCRIPT TYPE="text/javascript" SRC="complex.js"></SCRIPT>
    	<SCRIPT TYPE="text/javascript">
    		max_i = 10;   // 最大入り口数
    		max_q = 10;   // 最大待ち行列数
    		max_e = 10;   // 最大窓口数
    		function change(type, k1, k2)
    		{
    					// 入り口(Inlet)の数
    			if (type == 1) {
    				let n = parseInt(document.getElementById("n_i").value);
    				if (n <= 0 || n > max_i)
    					alert("***Error 入り口の数が不適当です");
    				else {
    					for (let i1 = 1; i1 <= n; i1++)
    						document.getElementById("n1"+i1).style.display = "";
    					for (let i1 = n+1; i1 <= max_i; i1++)
    						document.getElementById("n1"+i1).style.display = "none";
    				}
    			}
    					// 待ち行列(Queue)の数
    			else if (type == 2) {
    				let n = parseInt(document.getElementById("n_q").value);
    				if (n <= 0 || n > max_q)
    					alert("***Error 待ち行列の数が不適当です");
    				else {
    					for (let i1 = 1; i1 <= n; i1++)
    						document.getElementById("n2"+i1).style.display = "";
    					for (let i1 = n+1; i1 <= max_q; i1++)
    						document.getElementById("n2"+i1).style.display = "none";
    				}
    			}
    					// 窓口(Entity)の数
    			else if (type == 3) {
    				let n = parseInt(document.getElementById("n_e").value);
    				if (n <= 0 || n > max_e)
    					alert("***Error 窓口の数が不適当です");
    				else {
    					for (let i1 = 1; i1 <= n; i1++)
    						document.getElementById("n4"+i1).style.display = "";
    					for (let i1 = n+1; i1 <= max_e; i1++)
    						document.getElementById("n4"+i1).style.display = "none";
    				}
    			}
    					// 待ち行列
    			else if (type == 4) {
    							// 入り口の変更
    				if (k2 == 0) {
    					let n = parseInt(document.getElementById("qi"+k1).value);
    					if (n == 0) {
    						document.getElementById("n2"+k1+"0").style.display = "";
    						for (let i1 = 1; i1 <= max_e; i1++)
    							document.getElementById("n2"+k1+i1).style.display = "none";
    					}
    					else {
    						document.getElementById("n2"+k1+"0").style.display = "none";
    						for (let i1 = 1; i1 <= n; i1++)
    							document.getElementById("n2"+k1+i1).style.display = "";
    						for (let i1 = n+1; i1 <= max_e; i1++)
    							document.getElementById("n2"+k1+i1).style.display = "none";
    					}
    				}
    							// 出口の変更
    				else {
    					let n = parseInt(document.getElementById("qo"+k1).value);
    					if (n <= 0)
    						alert("error 0 以下にはできません");
    					else {
    						for (let i1 = 1; i1 <= n; i1++)
    							document.getElementById("n3"+k1+i1).style.display = "";
    						for (let i1 = n+1; i1 <= max_e; i1++)
    							document.getElementById("n3"+k1+i1).style.display = "none";
    					}
    				}
    			}
    					// 窓口における出口処理の変更
    			else if (type == 5) {
    				let n = parseInt(document.getElementById("eo"+k1).value);
    				if (n == 0)
    					document.getElementById("n5"+k1).style.display = "none";
    				else
    					document.getElementById("n5"+k1).style.display = "";
    			}
    					// 入り口における到着分布の変更
    			else if (type == 6) {
    				let n = parseInt(document.getElementById("a_t"+k1).value);
    				if (n == 0) {
    					document.getElementById("n11"+k1).style.display = "";
    					document.getElementById("n12"+k1).style.display = "none";
    					document.getElementById("man"+k1).innerHTML = "平均到着間隔";
    				}
    				else if (n == 1) {
    					document.getElementById("n11"+k1).style.display = "";
    					document.getElementById("n12"+k1).style.display = "none";
    					document.getElementById("man"+k1).innerHTML = "到着間隔";
    				}
    				else if (n < 0) {
    					document.getElementById("n11"+k1).style.display = "none";
    					document.getElementById("n12"+k1).style.display = "";
    				}
    			}
    					// 窓口におけるサービス分布の変更
    			else if (type == 7) {
    				let n = parseInt(document.getElementById("s_t"+k1).value);
    				if (n == 0)
    					document.getElementById("msn"+k1).innerHTML = "平均サービス時間";
    				else if (n == 1)
    					document.getElementById("msn"+k1).innerHTML = "サービス時間";
    			}
    		}
    	</SCRIPT>
    
    </HEAD>
    
    <BODY STYLE="font-size: 130%; background-color: #eeffee;">
    
    	<H2 STYLE="text-align:center"><B>複雑な待ち行列</B></H2>
    
    	<OL CLASS="no">
    		<DL>
    
    
    			<P STYLE="text-align:center">
    				シミュレーション時間:<INPUT ID="end" STYLE="font-size: 100%" TYPE="text" SIZE="2" VALUE="10000"> 
    				入り口(Inlet)の数(最大:10):<INPUT ID="n_i" STYLE="font-size: 100%" TYPE="text" SIZE="2" VALUE="2" onBlur="change(1, 0, 0)"><BR><BR>
    				待ち行列(Queue)の数(最大:10):<INPUT ID="n_q" STYLE="font-size: 100%" TYPE="text" SIZE="2" VALUE="3" onBlur="change(2, 0, 0)"> 
    				窓口(Entity)の数(最大:10):<INPUT ID="n_e" STYLE="font-size: 100%" TYPE="text" SIZE="2" VALUE="4" onBlur="change(3, 0, 0)">
    			</P>
    
    
    
    			<P STYLE="text-align:center">---入り口に対するデータ---</P>
    <SCRIPT TYPE="text/javascript">
    	let n_i = document.getElementById("n_i").value;
    	for (let i1 = 1; i1 <= max_i; i1++) {
    		document.write('			<DIV ID="n1' + i1 + '" STYLE="display: none">\n');
    		document.write('				<DT>入り口' + i1 + 'の名前:<INPUT ID="i' + i1 + '" STYLE="font-size: 100%" TYPE="text" SIZE="3" VALUE="Inlet' + i1 + '"></DT>\n');
    		document.write('				<DD>到着分布(=0:指数分布,=1:一定時間間隔,<0:指定,客数の負値):<INPUT ID="a_t' + i1 + '" STYLE="font-size: 100%" TYPE="text" SIZE="2" VALUE="0" onBlur="change(6, ' + i1 + ', 0)"></DD>\n');
    		document.write('				<DD ID="n11' + i1 + '">  <SPAN ID="man' + i1 + '">平均到着間隔</SPAN>:<INPUT ID="ma' + i1 + '" STYLE="font-size: 100%" TYPE="text" SIZE="2" VALUE="5"></DD>\n');
    		document.write('				<DD ID="n12' + i1 + '" STYLE="display: none">  到着時刻(半角スペースで区切って入力):<INPUT ID="at' + i1 + '" STYLE="font-size: 100%" TYPE="text" SIZE="30" VALUE=""></DD>\n');
    		document.write('				<DD>並ぶ待ち行列名:<INPUT ID="iq' + i1 + '" STYLE="font-size: 100%" TYPE="text" SIZE="3" VALUE="Queue' + i1 + '"></DD>\n');
    		document.write('			</DIV>\n');
    	}
    	for (let i1 = 1; i1 <= n_i; i1++)
    		document.getElementById("n1"+i1).style.display = "";
    </SCRIPT>
    
    
    
    			<P STYLE="text-align:center">---待ち行列に対するデータ---</P>
    <SCRIPT TYPE="text/javascript">
    	let n_q = document.getElementById("n_q").value;
    	for (let i1 = 1; i1 <= max_q; i1++) {
    		document.write('			<DIV ID="n2' + i1 + '" STYLE="display: none">\n');
    		document.write('				<DT>待ち行列' + i1 + 'の名前:<INPUT ID="q' + i1 + '" STYLE="font-size: 100%" TYPE="text" SIZE="3" VALUE="Queue' + i1 + '"></DT>\n');
    		document.write('				<DD>待ち行列へは,入り口(0)から or 窓口(n>0,窓口の数)から?:<INPUT ID="qi' + i1 + '" STYLE="font-size: 100%" TYPE="text" SIZE="2" VALUE="0" onBlur="change(4, ' + i1 + ', 0)"></DD>\n');
    		document.write('				<DD ID="n2' + i1 + '0">  待ち行列に入る入り口名:<INPUT ID="qii' + i1 + '1" STYLE="font-size: 100%" TYPE="text" SIZE="3" VALUE="Inlet' + i1 + '"></DD>\n');
    		for (let i2 = 1; i2 <= max_e; i2++)
    			document.write('				<DD ID="n2' + i1 + i2 + '" STYLE="display: none">  待ち行列に入る窓口名:<INPUT ID="qie' + i1 + i2 + '" STYLE="font-size: 100%" TYPE="text" SIZE="3" VALUE="Entity' + i2 + '"></DD>\n');
    		document.write('				<DD>待ち行列から出たとき,処理を行う窓口の数:<INPUT ID="qo' + i1 + '" STYLE="font-size: 100%" TYPE="text" SIZE="2" VALUE="1" onBlur="change(4, ' + i1 + ', 1)"></DD>\n');
    		for (let i2 = 1; i2 <= max_e; i2++)
    			document.write('				<DD ID="n3' + i1 + i2 + '" STYLE="display: none">  待ち行列を処理する窓口名:<INPUT ID="qoe' + i1 + i2 + '" STYLE="font-size: 100%" TYPE="text" SIZE="3" VALUE="Entity' + i1 + '"></DD>\n');
    		document.getElementById("n3"+i1+"1").style.display = "";
    		document.write('			</DIV>\n');
    	}
    	for (let i1 = 1; i1 <= n_q; i1++)
    		document.getElementById("n2"+i1).style.display = "";
    					// 例題のため変更
    	document.getElementById("n230").style.display = "none";
    	document.getElementById("qi3").value = "2";
    	for (let i1 = 1; i1 <= 2; i1++) {
    		document.getElementById("n23"+i1).style.display = "";
    		document.getElementById("qie3"+i1).value = "Entity" + i1;
    	}
    
    	document.getElementById("qo3").value = "2";
    	for (let i1 = 1; i1 <= 2; i1++) {
    		document.getElementById("n33"+i1).style.display = "";
    		document.getElementById("qoe3"+i1).value = "Entity" + (2+i1);
    	}
    </SCRIPT>
    
    
    
    			<P STYLE="text-align:center">---窓口に対するデータ---</P>
    <SCRIPT TYPE="text/javascript">
    	let n_e = document.getElementById("n_e").value;
    	for (let i1 = 1; i1 <= max_e; i1++) {
    		document.write('			<DIV ID="n4' + i1 + '" STYLE="display: none">\n');
    		document.write('				<DT>窓口' + i1 + 'の名前:<INPUT ID="e' + i1 + '" STYLE="font-size: 100%" TYPE="text" SIZE="3" VALUE="Entity' + i1 + '"></DT>\n');
    		document.write('				<DD>サービス分布(=0:指数分布,=1:一定時間):<INPUT ID="s_t' + i1 + '" STYLE="font-size: 100%" TYPE="text" SIZE="2" VALUE="0" onBlur="change(7, ' + i1 + ', 0)"> ');
    		document.write('				<SPAN ID="msn' + i1 + '">平均サービス時間</SPAN>:<INPUT ID="ms' + i1 + '" STYLE="font-size: 100%" TYPE="text" SIZE="2" VALUE="4"></DD>');
    		document.write('				<DD>処理対象の待ち行列名:<INPUT ID="eq' + i1 + '" STYLE="font-size: 100%" TYPE="text" SIZE="3" VALUE="Queue' + i1 + '"></DD>\n');
    		document.write('				<DD>処理終了後,外部(0),or,他の処理(1)?:<INPUT ID="eo' + i1 + '" STYLE="font-size: 100%" TYPE="text" SIZE="2" VALUE="0" onBlur="change(5, ' + i1 + ', 1)"></DD>\n');
    		document.write('				<DD ID="n5' + i1 + '" STYLE="display: none">  他の処理のための待ち行列名:<INPUT ID="eoq' + i1 + '" STYLE="font-size: 100%" TYPE="text" SIZE="3" VALUE="Queue' + i1 + '"></DD>\n');
    		document.write('			</DIV>\n');
    	}
    	for (let i1 = 1; i1 <= n_e; i1++)
    		document.getElementById("n4"+i1).style.display = "";
    					// 例題のため変更
    	for (let i1 = 1; i1 <= 2; i1++) {
    		document.getElementById("eo"+i1).value = "1";
    		document.getElementById("n5"+i1).style.display = "";
    		document.getElementById("eoq"+i1).value = "Queue3";
    	}
    	for (let i1 = 3; i1 <= 4; i1++) {
    		document.getElementById("ms"+i1).value = "3";
    		document.getElementById("eq"+i1).value = "Queue3";
    	}
    </SCRIPT>
    			<P STYLE="text-align:center">
    				<BUTTON STYLE="font-size: 100%; background-color: pink" onClick="main()">実行</BUTTON> 
    				結果は下<BR>
    				<TEXTAREA ID="res" COLS="70" ROWS="15" STYLE="font-size: 100%"></TEXTAREA>
    			</P>
    		</DL>
    	</OL>
    
    </BODY>
    
    </HTML>
    			

    complex.js

    /****************************/
    /* 複雑な待ち行列問題       */
    /*      coded by Y.Suganuma */
    /****************************/
    base = null;
    cus = new Array();   // 系内にいる客のリスト
    inl = new Array();   // Inletオブジェクトリスト
    que = new Array();   // Queueオブジェクトリスト
    ent = new Array();   // Entityオブジェクトリスト
    check = true;
    
    /****************/
    /* main program */
    /****************/
    function main()
    {
    	check = true;
    	cus.splice(0);   // 系内にいる客のリスト
    	inl.splice(0);   // Inletオブジェクトリスト
    	que.splice(0);   // Queueオブジェクトリスト
    	ent.splice(0);   // Entityオブジェクトリスト
    /*
              入力データ
    */
    					// 入り口
    	let n_i = parseInt(document.getElementById("n_i").value);   // 入り口(Inlet)の数
    	for (let i1 = 1; i1 <= n_i; i1++) {
    		let name1 = document.getElementById("i"+i1).value;   // 入り口の名前
    		let n     = parseInt(document.getElementById("a_t"+i1).value);   // 到着分布
    		let m_a   = 0;
    		let y     = new Array();
    		if (n == 0 || n == 1)
    			m_a = parseFloat(document.getElementById("ma"+i1).value);   // 平均到着時間間隔,到着時間間隔
    		else {
    			if (n > 0) {
    				alert("***error input1 人数が不適当です " + n);
    				check = false;
    			}
    			else {
    				let m = -n;
    				let x = document.getElementById("at"+i1).value.split(" ");
    				if (m != x.length) {
    					alert("***error input2 人数とデータ数が異なっています " + m + " "  + x.length);
    					check = false;
    				}
    				else {
    					for (let i2 = 0; i2 < m; i2++)
    						y.push(parseFloat(x[i2]));
    				}
    			}
    		}
    		let name2 = document.getElementById("iq"+i1).value;   // 並ぶ待ち行列の名前
    		let inl_e = new Inlet(name1, n, m_a, y, name2);
    		inl.push(inl_e);
    	}
    					// 待ち行列
    	let n_q = parseInt(document.getElementById("n_q").value);   // 待ち行列(Queue)の数
    	for (let i1 = 1; i1 <= n_q; i1++) {
    		let name1 = document.getElementById("q"+i1).value;   // 待ち行列の名前
    		let n = parseInt(document.getElementById("qi"+i1).value);   // 入り口(0),または,窓口(n>0,窓口の数)
    		let inn = new Array();
    		if (n == 0) {
    			let name2 = document.getElementById("qii"+i1+"1").value;   // 待ち行列の名前;
    			inn.push(name2);
    		}
    		else {
    			for (let i2 = 1; i2 <= n; i2++) {
    				let name3 = document.getElementById("qie"+i1+i2).value;   // 窓口の名前
    				inn.push(name3);
    			}
    		}
    		let m = parseInt(document.getElementById("qo"+i1).value);   // 処理する窓口の数
    		let out = new Array();
    		for (let i2 = 1; i2 <= m; i2++) {
    			let name4 = document.getElementById("qoe"+i1+i2).value;   // 窓口の名前
    			out.push(name4);
    		}
    		let que_e = new Queue(name1, n, inn, m, out);
    		que.push(que_e);
    	}
    					// 窓口
    	let n_e = parseInt(document.getElementById("n_e").value);   // 窓口(Entity)の数;
    	for (let i1 = 1; i1 <= n_e; i1++) {
    		let name1 = document.getElementById("e"+i1).value;   // 窓口の名前
    		let s_t = parseInt(document.getElementById("s_t"+i1).value);   // サービス分布
    		let m_s = parseFloat(document.getElementById("ms"+i1).value);   // 平均サービス時間,サービス時間
    		let name2 = document.getElementById("eq"+i1).value;   // 待ち行列(入力)の名前
    		let sw = parseInt(document.getElementById("eo"+i1).value);   // 外部(0),または,待ち行列(1)
    		let name3;
    		if (sw > 0)
    			name3 = document.getElementById("eoq"+i1).value;   // 待ち行列(出力)の名前
    		let ent_e = new Entity(name1, s_t, m_s, name2, sw, name3);
    		ent.push(ent_e);
    	}
    					// シミュレーション終了時間
    	let end = parseFloat(document.getElementById("end").value);   // シミュレーション終了時間
    
    	if (check) {
    		base = new Q_base(end)   // 全体の制御を行うクラス
    		if (check) {
    				// 実行
    			base.Control();
    					// 出力
    			base.Output();
    		}
    	}
    }
    
    /**********************/
    /* 指数分布乱数の発生 */
    /*      m : 平均値    */
    /*      rerutn : 乱数 */
    /**********************/
    function Exp_b(m)
    {
    	return -m * Math.log(Math.random());
    }
    
    /************************************************************/
    /* Inletオブジェクトの定義                                  */
    /*      name1 : 入り口名                                    */
    /*      a_t;   // = -n : 到着する客の人数を負の値にしたもの */
    /*             // =0 : 指数分布                             */
    /*             // =1 : 一定時間間隔                         */
    /*      m_a: 到着時間間隔またはその平均                    */
    /*      que : 客の到着時刻リスト                            */
    /*      name2 : 待ち行列名                                  */
    /************************************************************/
    function Inlet(name1, n, m_a, que, name2)
    {
    	this.name = name1;   // 入り口名
    	this.out = name2;   // 待ち行列名
    	this.out_n;   // 待ち行列番号
    	this.a_t = n;   // = -n : 到着する客の人数を負の値にしたもの
    	                // =0 : 指数分布
    	                // =1 : 一定時間間隔
    	this.mean = m_a;   // 到着時間間隔またはその平均
    	this.que = que;   // 客の到着時刻リスト
    	if (this.a_t == 0)   // 次の客の到着時刻(負:客がない)
    		this.arrive_time = Exp_b(this.mean);
    	else if (this.a_t == 1)
    		this.arrive_time = 0;
    	else
    		this.arrive_time = que.shift();
    
    	return this;
    }
    
    /*********************************************/
    /* Queueオブジェクトの定義                   */
    /*      name1 : 待ち行列名                   */
    /*      n1 : =0 : 入り口から入る             */
    /*           >0 : 複数の窓口から入る(窓口数) */
    /*      in1 : 入り口名,または,窓口名       */
    /*      m1 : 処理する窓口数                  */
    /*      out1 : 窓口名                        */
    /*********************************************/
    function Queue(name1, n1, in1, m1, out1)
    {
    	this.name = name1;   // 待ち行列名
    	this.nc = 0;   // 待ち行列への到着客数カウンタ
    	this.max_q_l = 0;   // 最大待ち行列長
    	this.c_ql = 0.0;   // 待ち行列長にその長さが継続した時間を乗じた値の累計
    	this.ql_t = 0.0;   // 現在の待ち行列長になった時間
    	this.max_wt = 0.0;   // 最大待ち時間
    	this.c_wt = 0.0;   // 待ち時間の累計
    	this.n = n1;   // =0 : 入り口から入る
    		           // >0 : 複数の窓口から入る(窓口数)
    	this.inn = in1;   // 入り口名,または,窓口名
    	this.in_n = new Array();   // 入り口番号,または,窓口番号
    	this.m = m1;   // 処理する窓口数
    	this.out = out1;   // 窓口名
    	this.out_n = new Array();   // 窓口番号
    	this.que = new Array();   // 待ち行列
    
    	return this;
    }
    
    /*************************************/
    /* Entityオブジェクトの定義          */
    /*      name1 : 窓口名               */
    /*		int s_t;   // =0 : 指数分布  */
    /*		           // =1 : 一定時間  */
    /*      m_s:平均サービス時間        */
    /*      name2 : 待ち行列(入力)の名前 */
    /*      sw : =0 : システムの外に出る */
    /*           =1 : 待ち行列に入る     */
    /*      name3 : 待ち行列(出力)の名前 */
    /*************************************/
    function Entity(name1, s_t, m_s, name2, sw, name3)
    {
    	this.name = name1;   // 窓口名
    	this.end_time = -1.0;   // サービス終了時刻(負:何も処理していない)
    	this.s_t = s_t;   // =0 : 指数分布
    		              // =1 : 一定時間
    	this.mean = m_s;   // 平均サービス時間
    	this.busy_t = -1.0;   // 窓口がふさがった時刻
    	this.c_busy = 0.0;   // 窓口がふさがっている時間の累計
    	this.service = 0;   // サービス中の客番号(0のときは無し)
    	this.inn = name2;   // 待ち行列(入力)の名前
    	this.in_n = 0;   // 待ち行列(入力)番号
    	this.to = sw;   // =0 : システムの外に出る
    		            // =1 : 待ち行列に入る
    	this.out = name3;   // 待ち行列(出力)の名前
    	this.out_n = 0;   // 待ち行列(出力)番号
    
    	return this;
    }
    
    /******************************/
    /* Customerオブジェクトの定義 */
    /*      n : 客番号            *
    /*      s1,s2 : 状態          */
    /*      t : 到着時刻          */
    /******************************/
    function Customer(n, s1, s2, t)
    {
    	this.num = n;   // 客番号
    	this.state1 = s1;   // 客の状態1
    	                    //   =0 : 待ち行列に入ってい
    	                    //   =1 : サービスを受けている
    	this.state2 = s2;   // 客の状態2(待ち行列番号,または,窓口番号)
    	this.time = t;   // 到着時刻
    
    	return this;
    }
    
    /*************************************/
    /* Q_baseオブジェクトの定義          */
    /*      e : シミュレーション終了時刻 */
    /*************************************/
    function Q_base(e)
    {
    	this.p_time = 0.0;  // 現在時刻
    	this.max_c = 0;   // 最大系内客数
    	this.nc = 0;   // システムへの到着客数カウンタ
    	this.now_c_t = 0.0;   // 現在の系内客数になった時間
    	this.c_now_c = 0.0;   // 系内客数にその数が継続した時間を乗じた値の累計
    	this.c_sys = 0.0;   // 滞在時間の累計
    	this.max_sys = 0.0;   // 最大滞在時間
    	this.end = e;   // シミュレーション終了時間
    					// 接続関係のチェック
    							// Inlet
    	for (let i1 = 0; i1 < inl.length-1; i1++) {
    		for (let i2 = i1+1; i2 < inl.length; i2++) {
    			if (inl[i1].name == inl[i2].name) {
    				alert("***error1 同じ名前の入り口があります " + inl[i1].name);
    				check = false;
    			}
    		}
    	}
    
    	let k;
    	for (let i1 = 0; i1 < inl.length; i1++) {
    		k = -1;
    		for (let i2 = 0; i2 < que.length; i2++) {
    			if (inl[i1].out == que[i2].name) {
    				k = i2;
    				break;
    			}
    		}
    		if (k >= 0)
    			inl[i1].out_n = k;
    		else {
    			alert("***error2 入り口から入る待ち行列名が不適当です " + inl[i1].out);
    			check = false;
    		}
    	}
    							// Queue
    	for (let i1 = 0; i1 < que.length-1; i1++) {
    		for (let i2 = i1+1; i2 < que.length; i2++) {
    			if (que[i1].name == que[i2].name) {
    				alert("***error3 同じ名前の待ち行列があります " + que[i1].name);
    				check = false;
    			}
    		}
    	}
    
    	for (let i1 = 0; i1 < que.length; i1++) {
    		if (que[i1].n == 0) {
    			k = -1;
    			for (let i2 = 0; i2 < inl.length; i2++) {
    				if (que[i1].inn[0] == inl[i2].name) {
    					k = i2;
    					break;
    				}
    			}
    			if (k >= 0)
    				que[i1].in_n.push(k);
    			else {
    				alert("***error4 待ち行列に入る入り口名が不適当です " + que[i1].inn[0]);
    				check = false;
    			}
    		}
    		else {
    			for (let i2 = 0; i2 < que[i1].n; i2++) {
    				k = -1;
    				for (let i3 = 0; i3 < ent.length; i3++) {
    					if (que[i1].inn[i2] == ent[i3].name) {
    						k = i3;
    						break;
    					}
    				}
    				if (k >= 0)
    					que[i1].in_n.push(k);
    				else {
    					alert("***error5 待ち行列に入る窓口名が不適当です " + que[i1].inn[i2]);
    					check = false;
    				}
    			}
    		}
    		for (let i2 = 0; i2 < que[i1].m; i2++) {
    			k = -1;
    			for (let i3 = 0; i3 < ent.length; i3++) {
    				if (que[i1].out[i2] == ent[i3].name) {
    					k = i3;
    					break;
    				}
    			}
    			if (k >= 0)
    				que[i1].out_n.push(k);
    			else {
    				alert("***error6 待ち行列を処理する窓口名が不適当です " + que[i1].out[i2]);
    				check = false;
    			}
    		}
    	}
    							// Entity
    	for (let i1 = 0; i1 < ent.length-1; i1++) {
    		k = -1;
    		for (let i2 = i1+1; i2 < ent.length; i2++) {
    			if (ent[i1].name == ent[i2].name) {
    				alert("***error7 同じ名前の窓口があります " + ent[i1].name);
    				check = false;
    			}
    		}
    	}
    
    	for (let i1 = 0; i1 < ent.length; i1++) {
    		k = -1;
    		for (let i2 = 0; i2 < que.length; i2++) {
    			if (ent[i1].inn == que[i2].name) {
    				k = i2;
    				break;
    			}
    		}
    		if (k >= 0)
    			ent[i1].in_n = k;
    		else {
    			alert("***error8 窓口に入る待ち行列名が不適当です " + ent[i1].inn);
    			check = false;
    		}
    		if (ent[i1].to > 0) {
    			k = -1;
    			for (let i2 = 0; i2 < que.length; i2++) {
    				if (ent[i1].out == que[i2].name) {
    					k = i2;
    					break;
    				}
    			}
    			if (k >= 0)
    				ent[i1].out_n = k;
    			else {
    				alert("***error9 窓口の出口にある待ち行列名が不適当です " + ent[i1].out);
    				check = false;
    			}
    		}
    	}
    
    	return this;
    }
    
    /**************/
    /* 全体の制御 */
    /**************/
    Q_base.prototype.Control = function()
    {
    	let sw = new Array(2);
    	sw[0]  = 0;
    	while (sw[0] > -2) {
    		base.Next(sw);   // 次の処理の選択
    		if (sw[0] == -1)
    			sw[0] = base.End_o_s();   // シミュレーションの終了
    		else {
    			if (sw[0] == 0)
    				base.Arrive(sw[1]);   // 客の到着処理
    			else
    				base.Service(sw[1]);   // サービスの終了
    		}
    	}
    }
    
    /*********************************************/
    /* 次の処理の決定                            */
    /*      sw[0] : =-1 : シミュレーションの終了 */
    /*              =0  : 客の到着処理           */
    /*              =1  : 窓口のサービス終了     */
    /*        [1] : 入り口番号 or 窓口番号       */
    /*********************************************/
    Q_base.prototype.Next = function(sw)
    {
    	let tm = base.end;   // 次の処理時刻
    	sw[0]  = -1;
    					// 次の客の到着時刻
    	for (let i1 = 0; i1 < inl.length; i1++) {
    		let x = inl[i1];
    		if (x.arrive_time >= 0.0 && x.arrive_time < tm) {
    			sw[0] = 0;
    			sw[1] = i1;
    			tm    = x.arrive_time;
    		}
    	}
    					// サービス終了時刻
    	for (let i1 = 0; i1 < ent.length; i1++) {
    		let x = ent[i1];
    		if (x.service > 0 && x.end_time <= tm) {
    			sw[0] = 1;
    			sw[1] = i1;
    			tm    = x.end_time;
    		}
    	}
    
    	if (sw[0] < 0)
    		base.end = base.p_time;
    
    	return sw;
    }
    
    /**********************************/
    /* 終了処理                       */
    /*      return : =-1 : 終了前処理 */
    /*               =-2 : 実際の終了 */
    /**********************************/
    Q_base.prototype.End_o_s = function()
    {
    	let sw = -2;
    	base.p_time = base.end;   // 現在時刻
    
    	for (let i1 = 0; i1 < ent.length; i1++) {
    		let x = ent[i1];
    		if (x.service > 0) {   // サービス中の客はいるか?
    			if (sw == -2) {
    				sw = -1;
    				base.end = x.end_time;   // 窓口i1のサービス終了時刻
    			}
    			else {
    				if (x.end_time > base.end)
    					base.end = x.end_time;   // 窓口i1のサービス終了時刻
    			}
    		}
    	}
    
    	return sw;
    }
    
    /************************/
    /* 客の到着処理         */
    /*      kk : 入り口番号 */
    /************************/
    Q_base.prototype.Arrive = function(kk)
    {
    /*
              客数の増加と次の客の到着時刻の設定
    */
    	base.nc     += 1;   // 到着客数カウンタ
    	base.p_time  = inl[kk].arrive_time;   // 現在時刻
    	if (inl[kk].a_t == 0)   // 次の客の到着時刻
    		inl[kk].arrive_time = base.p_time + Exp_b(inl[kk].mean);   
    	else if (inl[kk].a_t == 1)
    		inl[kk].arrive_time = base.p_time + inl[kk].mean;   
    	else {
    		if (inl[kk].que.length <= 0)
    			inl[kk].arrive_time = -1.0;
    		else
    			inl[kk].arrive_time = inl[kk].que.shift();
    	}
    	if (inl[kk].arrive_time >= base.end)
    		inl[kk].arrive_time = -1.0;
    /*
              系内客数の処理
    */
    	base.c_now_c += cus.length * (base.p_time - base.now_c_t);   // 系内客数にその数が継続した時間を乗じた値の累計
    	base.now_c_t  = base.p_time;   // 現在の系内客数になった時刻
    	if (cus.length+1 > base.max_c)
    		base.max_c = cus.length + 1;   // 最大系内客数
    /*
              空いている窓口を探す
    */
    	let k1 = inl[kk].out_n;
    	que[k1].nc++;
    	let k = -1;
    	for (let i1 = 0; i1 < que[k1].m; i1++) {
    		let k2 = que[k1].out_n[i1];   // 処理窓口
    		if (ent[k2].service == 0) {
    			k = k2;
    			break;
    		}
    	}
    /*
              窓口に空きがない場合
    */
    	if (k < 0) {
    		let ct_p = new Customer(base.nc, 0, k1, base.p_time);
    		cus.push(ct_p);   // 客の登録(系内客数)
    		que[k1].c_ql += que[k1].que.length * (base.p_time - que[k1].ql_t);   // 待ち行列長にその長さが継続した時間を乗じた値の累計
    		que[k1].que.push(base.nc);   // 客の登録(待ち行列)
    		que[k1].ql_t = base.p_time;   // 現在の待ち行列長になった時刻
    		if (que[k1].que.length > que[k1].max_q_l)
    			que[k1].max_q_l = que[k1].que.length;   // 最大待ち行列長
    	}
    /*
              すぐサービスをうけられる場合
    */
    	else {
    		let ct_p = new Customer(base.nc, 1, k, base.p_time);
    		cus.push(ct_p);   // 客の登録(系内客数)
    		ent[k].service  = base.nc;   // サービスを受けている客番号
    		ent[k].busy_t   = base.p_time;   // 窓口がふさがった時刻
    		if (ent[k].s_t == 0)   // 窓口のサービス終了時刻
    			ent[k].end_time = base.p_time + Exp_b(ent[k].mean);
    		else
    			ent[k].end_time = base.p_time + ent[k].mean;
    	}
    }
    
    /**********************************/
    /* サービス終了時の処理           */
    /*      kk : サービス終了窓口番号 */
    /**********************************/
    Q_base.prototype.Service = function(kk)
    {
    /*
              時間の設定
    */
    	base.p_time = ent[kk].end_time;   // 現在時刻
    	ent[kk].end_time = -1.0;   // サービス終了時間
    /*
              システムの外へ出る場合
    */
    	if (ent[kk].to == 0) {
    /*
                   系内客数の処理
    */
    		base.c_now_c += cus.length * (base.p_time - base.now_c_t);   // 系内客数にその数が継続した時間を乗じた値の累計
    		base.now_c_t  = base.p_time;   // 現在の系内客数になった時刻
    /*
                   滞在時間の処理
    */
    		let n  = base.Search(ent[kk].service);   // サービス中の客
    		let x1 = base.p_time - cus[n].time;
    		base.c_sys += x1;   // 滞在時間の累計
    		if (x1 > base.max_sys)
    			base.max_sys = x1;   // 最大滞在時間
    		cus.splice(n, 1);   // 客の削除(系内客数)
    	}
    /*
              他の窓口処理へ入る場合の処理
    */
    	else {
    		let k1 = ent[kk].out_n;
    		que[k1].nc++;
    		let sw = 1;
    		let k2 = 0;
    		if (que[k1].que.length == 0) {
    			for (let i1 = 0; i1 < que[k1].m; i1++) {
    				k2 = que[k1].out_n[i1];   // 窓口
    				if (ent[k2].service == 0) {
    					sw = 0;
    					break;
    				}
    			}
    		}
    /*
                   待ち行列がある場合
    */
    		if (sw > 0) {
    			que[k1].c_ql += que[k1].que.length * (base.p_time - que[k1].ql_t);   // 待ち行列長にその長さが継続した時間を乗じた値の累計
    			que[k1].que.push(ent[kk].service);   // 客の登録(待ち行列)
    			que[k1].ql_t = base.p_time;   // 現在の待ち行列長になった時刻
    			if (que[k1].que.length > que[k1].max_q_l)
    				que[k1].max_q_l = que[k1].que.length;   // 最大待ち行列長
    			let m = base.Search(ent[kk].service);
    			cus[m].state1 = 0;   // 客の状態変更(待ち行列)
    			cus[m].state2 = ent[kk].out_n;   // 客の状態変更(待ち行列番号)
    		}
    /*
                   すぐサービスをうけられる場合
    */
    		else {
    			ent[k2].service  = ent[kk].service;   // サービスを受けている客番号
    			ent[k2].busy_t   = base.p_time;   // 窓口がふさがった時刻
    			if (ent[k2].s_t == 0)   // 窓口のサービス終了時刻
    				ent[k2].end_time = base.p_time + Exp_b(ent[k2].mean);
    			else
    				ent[k2].end_time = base.p_time + ent[k2].mean;
    		}
    	}
    /*
              窓口使用時間の処理
    */
    	ent[kk].service  = 0;   // 窓口を空き状態にする
    	ent[kk].c_busy  += (base.p_time - ent[kk].busy_t);   // 窓口がふさがっている時間の累計
    /*
              この窓口に対する待ち行列がある場合
    */
    	let k3 = ent[kk].in_n;
    	if (que[k3].que.length > 0) {
    		que[k3].c_ql += que[k3].que.length * (base.p_time - que[k3].ql_t);   // 待ち行列長にその長さが継続した時間を乗じた値の累計
    		let n = que[k3].que.shift();   // 待ち行列の先頭にいる客の削除
    		que[k3].ql_t =  base.p_time;   // 現在の待ち行列長になった時刻
    		let m  = base.Search(n);
    		x1 = base.p_time - cus[m].time;
    		que[k3].c_wt += x1;   // 待ち時間の累計
    		if (x1 > que[k3].max_wt)
    			que[k3].max_wt = x1;   // 最大待ち時間
    		for (let i1 = 0; i1 < que[k3].m; i1++) {
    			let k4 = que[k3].out_n[i1];   // 窓口
    			if (ent[k4].service == 0) {
    				ent[k4].service = n;   // 窓口の客番号
    				ent[k4].busy_t  = base.p_time;   // 窓口がふさがった時刻
    				if (ent[k4].s_t == 0)   // 窓口のサービス終了時刻
    					ent[k4].end_time = base.p_time + Exp_b(ent[k4].mean);
    				else
    					ent[k4].end_time = base.p_time + ent[k4].mean;
    				cus[m].state1 = 1;   // 客の状態変更(サービス中)
    				cus[m].state2 = k4;   // 客の状態変更(窓口番号)
    				break;
    			}
    		}
    	}
    }
    
    /****************************/
    /* 指定した客の配列上の位置 */
    /*      nm : 客番号         */
    /*      return : 要素番号   */
    /****************************/
    Q_base.prototype.Search = function(nm)
    {
    	let n = -1;
    
    	for (let i1 = 0; i1 < cus.length; i1++) {
    		if (cus[i1].num == nm) {
    			n = i1;
    			break;
    		}
    	}
    
    	return n;
    }
    
    /**************************/
    /* 統計量の計算と最終出力 */
    /**************************/
    Q_base.prototype.Output = function()
    {
    					// System
    	let str = "全客数 " + base.nc;
    	str += " 最大系内客数 " + base.max_c + " 最大滞在時間 " + Math.round(1000*base.max_sys)/1000 + "\n";
    	str += "平均系内客数 " + Math.round(1000*base.c_now_c/base.p_time)/1000;
    	str += " 平均滞在時間 " + Math.round(1000*base.c_sys/base.nc)/1000;
    	str += " 終了時間 " + Math.round(1000*base.p_time)/1000 + "\n";
    					// Entity
    	for (let i1 = 0; i1 < ent.length; i1++) {
    		let e = ent[i1];
    		str += "Entity " + e.name;
    		str += " 稼働率 " + Math.round(1000*e.c_busy/base.p_time)/1000 + "\n";
    	}
    					// Queue
    	for (let i1 = 0; i1 < que.length; i1++) {
    		let q = que[i1];
    		str += "Queue " + q.name;
    		str += " 客数 " + q.nc;
    		str += "   最大待ち行列長 " + q.max_q_l;
    		str += "   最大待ち時間 " + Math.round(1000*q.max_wt)/1000 + "\n";
    		str += "      平均待ち行列長 " + Math.round(1000*q.c_ql/base.p_time)/1000;
    		str += "   平均待ち時間 " + Math.round(1000*q.c_wt/q.nc)/1000 + "\n";
    	}
    
    	document.getElementById("res").value = str;
    }
    			

  4. PHP

    <?php
    
    /******************************/
    /* 複雑な待ち行列問題         */
    /*      coded by Y.Suganuma   */
    /******************************/
    
    /**********************/
    /* 指数分布乱数の発生 */
    /*      m : 平均値    */
    /*      rerutn : 乱数 */
    /**********************/
    function Exp_b($m)
    {
    	return -$m * log(mt_rand() / mt_getrandmax());
    }
    
    /*********************/
    /* クラスInletの定義 */
    /*********************/
    class Inlet {
    	public $name;   // 入り口名
    	public $out;   // 待ち行列名
    	public $out_n;   // 待ち行列番号
    	public $arrive_time;   // 客の到着時刻(負:客がない)
    	public $a_t;   // = -n : 到着する客の人数を負の値にしたもの
    		           // =0 : 指数分布
    		           // =1 : 一定時間間隔
    	public $mean;   // 到着時間間隔またはその平均
    	public $que;   // 客の到着時刻リスト
    
    	/*************************************************************/
    	/* コンストラクタ                                            */
    	/*      name1 : 入り口名                                     */
    	/*      a_t1;   // = -n : 到着する客の人数を負の値にしたもの */
    	/*              // =0 : 指数分布                             */
    	/*              // =1 : 一定時間間隔                         */
    	/*      m_a: 到着時間間隔またはその平均                     */
    	/*      que1 : 客の到着時刻リスト                            */
    	/*      name2 : 待ち行列名                                   */
    	/*************************************************************/
    	function Inlet ($name1, $a_t1, $m_a, $que1, $name2)
    	{
    		$this->name = $name1;
    		$this->out  = $name2;
    		$this->a_t  = $a_t1;
    		$this->mean = $m_a;
    		if ($this->a_t == 0)
    			$this->arrive_time = Exp_b($this->mean);
    		else if ($this->a_t == 1)
    			$this->arrive_time = 0;
    		else {
    			$this->que         = $que1;
    			$this->arrive_time = array_shift($this->que);
    		}
    	}
    }
    
    /*********************/
    /* クラスQueueの定義 */
    /*********************/
    class Queue {
    	public $name;   // 待ち行列名
    	public $nc;   // 待ち行列への到着客数カウンタ
    	public $max_q_l;   // 最大待ち行列長
    	public $c_ql;   // 待ち行列長にその長さが継続した時間を乗じた値の累計
    	public $ql_t;   // 現在の待ち行列長になった時間
    	public $max_wt;   // 最大待ち時間
    	public $c_wt;   // 待ち時間の累計
    	public $n;   // =0 : 入り口から入る
    	             // >0 : 複数の窓口から入る(窓口数)
    	public $in;   // 入り口名,または,窓口名
    	public $in_n;   // 入り口番号,または,窓口番号
    	public $m;   // 処理する窓口数
    	public $out;   // 窓口名
    	public $out_n;   // 窓口番号
    	public $que;   // 待ち行列
    
    	/*********************************************/
    	/* コンストラクタ                            */
    	/*      name1 : 待ち行列名                   */
    	/*      n1 : =0 : 入り口から入る             */
    	/*           >0 : 複数の窓口から入る(窓口数) */
    	/*      in1 : 入り口名,または,窓口名       */
    	/*      m1 : 処理する窓口数                  */
    	/*      out1 : 窓口名                        */
    	/*********************************************/
    	function Queue($name1, $n1, $in1, $m1, $out1)
    	{
    		$this->name    = $name1;
    		$this->n       = $n1;
    		$this->in      = $in1;
    		$this->m       = $m1;
    		$this->out     = $out1;
    		$this->nc      = 0;
    		$this->max_q_l = 0;
    		$this->c_ql    = 0.0;
    		$this->ql_t    = 0.0;
    		$this->max_wt  = 0.0;
    		$this->c_wt    = 0.0;
    		$this->in_n    = array();
    		$this->out_n   = array();
    		$this->que     = array();
    	}
    }
    
    /**********************/
    /* クラスEntityの定義 */
    /**********************/
    class Entity {
    	public $name;   // 窓口名
    	public $end_time;   // サービス終了時刻(負:何も処理していない)
    	public $s_t;   // =0 : 指数分布
    	               // =1 : 一定時間
    	public $mean;   // 平均サービス時間
    	public $busy_t;   // 窓口がふさがった時刻
    	public $c_busy;   // 窓口がふさがっている時間の累計
    	public $service;   // サービス中の客番号(0のときは無し)
    	public $in;   // 待ち行列(入力)の名前
    	public $in_n;   // 待ち行列(入力)番号
    	public $to;   // =0 : システムの外に出る
    	              // =1 : 待ち行列に入る
    	public $out;   // 待ち行列(出力)の名前
    	public $out_n;   // 待ち行列(出力)番号
    	
    	/****************************************/
    	/* コンストラクタ                       */
    	/*      name1 : 窓口名                  */
    	/*      s_t1;   // =0 : 指数分布        */
    	/*              // =1 : 一定時間        */
    	/*      m_s:サービス時間またはその平均 */
    	/*      name2 : 待ち行列(入力)の名前    */
    	/*      sw : =0 : システムの外に出る    */
    	/*           =1 : 待ち行列に入る        */
    	/*      name3 : 待ち行列(出力)の名前    */
    	/**********************************+++***/
    	function Entity($name1, $s_t1, $m_s, $name2, $sw, $name3)
    	{
    		$this->name = $name1;
    		$this->to   = $sw;
    		$this->in   = $name2;
    		if ($this->to > 0)
    			$this->out = $name3;
    		$this->end_time = -1.0;
    		$this->s_t      = $s_t1;
    		$this->mean     = $m_s;
    		$this->service  = 0;
    		$this->busy_t   = -1.0;
    		$this->c_busy   = 0.0;
    	}
    }
    
    /************************/
    /* クラスCustomerの定義 */
    /************************/
    class Customer
    {
    	public $time;   // 到着時刻
    	public $state1;   // 客の状態1
                          //   =0 : 待ち行列に入っている
                          //   =1 : サービスを受けている
    	public $state2;   // 客の状態2(待ち行列番号,または,窓口番号)
    
    	/*********************/
    	/* コンストラクタ    */
    	/*      s1,s2 : 状態 */
    	/*      t : 到着時刻 */
    	/*******************************/
    	function Customer($s1, $s2, $t)
    	{
    		$this->time   = $t;
    		$this->state1 = $s1;
    		$this->state2 = $s2;
    	}
    }
    
    /**********************/
    /* クラスQ_baseの定義 */
    /**********************/
    class Q_base {
    	public $p_time;  // 現在時刻
    	public $max_c;   // 最大系内客数
    	public $nc;   // システムへの到着客数カウンタ
    	public $now_c_t;   // 現在の系内客数になった時間
    	public $c_now_c;   // 系内客数にその数が継続した時間を乗じた値の累計
    	public $c_sys;   // 滞在時間の累計
    	public $max_sys;   // 最大滞在時間
    	public $end;   // シミュレーション終了時間
    	public $cus;   // 系内にいる客のリスト
    	public $inl;   // Inletオブジェクトリスト
    	public $que;   // Queueオブジェクトリスト
    	public $ent;   // Entityオブジェクトリスト
    
    	/***************************************/
    	/* コンストラクタ                      */
    	/*      v_i : Inletオブジェクトリスト  */
    	/*      v_q : Queueオブジェクトリスト  */
    	/*      v_e : Entityオブジェクトリスト */
    	/*      e : シミュレーション終了時刻   */
    	/***************************************/
    	function Q_base($v_i, $v_q, $v_e, $e)
    	{
    				// 接続関係のチェック
    		print("\n");
    						// Inlet
    		$this->inl = $v_i;
    		$this->que = $v_q;
    		$this->ent = $v_e;
    		for ($i1 = 0; $i1 < count($this->inl)-1; $i1++) {
    			for ($i2 = $i1+1; $i2 < count($this->inl); $i2++) {
    				if ($this->inl[$i1]->name == $this->inl[$i2]->name)
    					exit("***error 同じ名前の入り口があります ".$this->inl[$i1]->name."\n");
    			}
    		}
    
    		$k;
    		for ($i1 = 0; $i1 < count($this->inl); $i1++) {
    			$k = -1;
    			for ($i2 = 0; $i2 < count($this->que); $i2++) {
    				if ($this->inl[$i1]->out == $this->que[$i2]->name) {
    					$k = $i2;
    					break;
    				}
    			}
    			if ($k >= 0)
    				$this->inl[$i1]->out_n = $k;
    			else
    				exit("***error 入り口から入る待ち行列名が不適当です ".$this->inl[$i1]->out."\n");
    		}
    						// Queue
    		for ($i1 = 0; $i1 < count($this->que)-1; $i1++) {
    			for ($i2 = $i1+1; $i2 < count($this->que); $i2++) {
    				if ($this->que[$i1]->name == $this->que[$i2]->name)
    					exit("***error 同じ名前の待ち行列があります ".$this->que[$i1]->name."\n");
    			}
    		}
    
    		for ($i1 = 0; $i1 < count($this->que); $i1++) {
    			if ($this->que[$i1]->n == 0) {
    				$k = -1;
    				for ($i2 = 0; $i2 < count($this->inl); $i2++) {
    					if ($this->que[$i1]->in[0] == $this->inl[$i2]->name) {
    						$k = $i2;
    						break;
    					}
    				}
    				if ($k >= 0)
    					array_push($this->que[$i1]->in_n, $k);
    				else
    					exit("***error 待ち行列に入る入り口名が不適当です ".$this->que[$i1]->in[0]."\n");
    			}
    			else {
    				for ($i2 = 0; $i2 < $this->que[$i1]->n; $i2++) {
    					$k = -1;
    					for ($i3 = 0; $i3 < count($this->ent); $i3++) {
    						if ($this->que[$i1]->in[$i2] == $this->ent[$i3]->name) {
    							$k = $i3;
    							break;
    						}
    					}
    					if ($k >= 0)
    						array_push($this->que[$i1]->in_n, $k);
    					else
    						exit("***error 待ち行列に入る窓口名が不適当です ".$this->que[$i1]->in[$i2]."\n");
    				}
    			}
    			for ($i2 = 0; $i2 < $this->que[$i1]->m; $i2++) {
    				$k = -1;
    				for ($i3 = 0; $i3 < count($this->ent); $i3++) {
    					if ($this->que[$i1]->out[$i2] == $this->ent[$i3]->name) {
    						$k = $i3;
    						break;
    					}
    				}
    				if ($k >= 0)
    					array_push($this->que[$i1]->out_n, $k);
    				else
    					exit("***error 待ち行列を処理する窓口名が不適当です ".$this->que[$i1]->out[$i2]."\n");
    			}
    		}
    						// Entity
    		for ($i1 = 0; $i1 < count($this->ent)-1; $i1++) {
    			$k = -1;
    			for ($i2 = $i1+1; $i2 < count($this->ent); $i2++) {
    				if ($this->ent[$i1]->name == $this->ent[$i2]->name)
    					exit("***error 同じ名前の窓口があります ".$this->ent[$i1]->name."\n");
    			}
    		}
    
    		for ($i1 = 0; $i1 < count($this->ent); $i1++) {
    			$k = -1;
    			for ($i2 = 0; $i2 < count($this->que); $i2++) {
    				if ($this->ent[$i1]->in == $this->que[$i2]->name) {
    					$k = $i2;
    					break;
    				}
    			}
    			if ($k >= 0)
    				$this->ent[$i1]->in_n = $k;
    			else
    				exit("***error 窓口に入る待ち行列名が不適当です ".$this->ent[$i1]->in."\n");
    			if ($this->ent[$i1]->to > 0) {
    				$k = -1;
    				for ($i2 = 0; $i2 < count($this->que); $i2++) {
    					if ($this->ent[$i1]->out == $this->que[$i2]->name) {
    						$k = $i2;
    						break;
    					}
    				}
    				if ($k >= 0)
    					$this->ent[$i1]->out_n = $k;
    				else
    					exit("***error 窓口の出口にある待ち行列名が不適当です ".$this->ent[$i1]->out."\n");
    			}
    		}
    				// 初期設定
    		$this->p_time  = 0.0;
    		$this->max_c   = 0;
    		$this->nc      = 0;
    		$this->now_c_t = 0.0;
    		$this->c_now_c = 0.0;
    		$this->c_sys   = 0.0;
    		$this->max_sys = 0.0;
    		$this->end     = $e;
    		$this->cus     = array();
    				// 乱数の初期設定
    		mt_srand();
    	}
    
    	/**************/
    	/* 全体の制御 */
    	/**************/
    	function Control()
    	{
    		$sw    = array(2);
    		$sw[0] = 0;
    		while ($sw[0] > -2) {
    			$this->Next($sw);   // 次の処理の選択
    			if ($sw[0] == -1)
    				$sw[0] = $this->End_o_s();   // シミュレーションの終了
    			else {
    				if ($sw[0] == 0)
    					$this->Arrive($sw[1]);   // 客の到着処理
    				else
    					$this->Service($sw[1]);   // サービスの終了
    			}
    		}
    	}
    	
    	/*********************************************/
    	/* 次の処理の決定                            */
    	/*      sw[0] : =-1 : シミュレーションの終了 */
    	/*              =0  : 客の到着処理           */
    	/*              =1  : 窓口のサービス終了     */
    	/*        [1] : 入り口番号 or 窓口番号       */
    	/*********************************************/
    	function Next(&$sw)
    	{
    		$tm    = $this->end;   // 次の処理時刻
    		$sw[0] = -1;
    						// 次の客の到着時刻
    		for ($i1 = 0; $i1 < count($this->inl); $i1++) {
    			$x = $this->inl[$i1];
    			if ($x->arrive_time >= 0.0 && $x->arrive_time < $tm) {
    				$sw[0] = 0;
    				$sw[1] = $i1;
    				$tm    = $x->arrive_time;
    			}
    		}
    						// サービス終了時刻
    		for ($i1 = 0; $i1 < count($this->ent); $i1++) {
    			$x = $this->ent[$i1];
    			if ($x->service > 0 && $x->end_time <= $tm) {
    				$sw[0] = 1;
    				$sw[1] = $i1;
    				$tm    = $x->end_time;
    			}
    		}
    	
    		if ($sw[0] < 0)
    			$this->end = $this->p_time;
    	}
    	
    	/**********************************/
    	/* 終了処理                       */
    	/*      return : =-1 : 終了前処理 */
    	/*               =-2 : 実際の終了 */
    	/**********************************/
    	function End_o_s()
    	{
    		$sw           = -2;
    		$this->p_time = $this->end;   // 現在時刻
    	
    		for ($i1 = 0; $i1 < count($this->ent); $i1++) {
    			$x = $this->ent[$i1];
    			if ($x->service > 0) {   // サービス中の客はいるか?
    				if ($sw == -2) {
    					$sw = -1;
    					$this->end = $x->end_time;   // 窓口$i1のサービス終了時刻
    				}
    				else {
    					if ($x->end_time > $this->end)
    						$this->end = $x->end_time;   // 窓口$i1のサービス終了時刻
    				}
    			}
    		}
    	
    		return $sw;
    	}
    	
    	/************************/
    	/* 客の到着処理         */
    	/*      kk : 入り口番号 */
    	/************************/
    	function Arrive($kk)
    	{
    	/*
    	          客数の増加と次の客の到着時刻の設定
    	*/
    		$this->nc     += 1;   // 到着客数カウンタ
    		$this->p_time  = $this->inl[$kk]->arrive_time;   // 現在時刻
    		if ($this->inl[$kk]->a_t == 0)   // 次の客の到着時刻
    			$this->inl[$kk]->arrive_time = $this->p_time + Exp_b($this->inl[$kk]->mean);   
    		else if ($this->inl[$kk]->a_t == 1)
    			$this->inl[$kk]->arrive_time = $this->p_time + $this->inl[$kk]->mean;   
    		else {
    			if (count($this->inl[$kk]->que) <= 0)
    				$this->inl[$kk]->arrive_time = -1.0;
    			else
    				$this->inl[$kk]->arrive_time = array_shift($this->inl[$kk]->que);
    		}
    		if ($this->inl[$kk]->arrive_time >= $this->end)
    			$this->inl[$kk]->arrive_time = -1.0;
    	/*
    	          系内客数の処理
    	*/
    		$this->c_now_c += count($this->cus) * ($this->p_time - $this->now_c_t);   // 系内客数にその数が継続した時間を乗じた値の累計
    		$this->now_c_t  = $this->p_time;   // 現在の系内客数になった時刻
    		if (count($this->cus)+1 > $this->max_c)
    			$this->max_c = count($this->cus) + 1;   // 最大系内客数
    	/*
    	          空いている窓口を探す
    	*/
    		$k1 = $this->inl[$kk]->out_n;
    		$this->que[$k1]->nc++;
    		$k = -1;
    		for ($i1 = 0; $i1 < $this->que[$k1]->m; $i1++) {
    			$k2 = $this->que[$k1]->out_n[$i1];   // 処理窓口
    			if ($this->ent[$k2]->service == 0) {
    				$k = $k2;
    				break;
    			}
    		}
    	/*
    	          窓口に空きがない場合
    	*/
    		if ($k < 0) {
    			$ct_p = new Customer(0, $k1, $this->p_time);
    			$this->cus['no'.strval($this->nc)] = $ct_p;   // 客の登録(系内客数)
    			$this->que[$k1]->c_ql += count($this->que[$k1]->que) * ($this->p_time - $this->que[$k1]->ql_t);   // 待ち行列長にその長さが継続した時間を乗じた値の累計
    			array_push($this->que[$k1]->que, $this->nc);   // 客の登録(待ち行列)
    			$this->que[$k1]->ql_t = $this->p_time;   // 現在の待ち行列長になった時刻
    			if (count($this->que[$k1]->que) > $this->que[$k1]->max_q_l)
    				$this->que[$k1]->max_q_l = count($this->que[$k1]->que);   // 最大待ち行列長
    		}
    	/*
    	          すぐサービスをうけられる場合
    	*/
    		else {
    			$ct_p = new Customer(1, $k, $this->p_time);
    			$this->cus['no'.strval($this->nc)] = $ct_p;   // 客の登録(系内客数)
    			$this->ent[$k]->service = $this->nc;   // サービスを受けている客番号
    			$this->ent[$k]->busy_t  = $this->p_time;   // 窓口がふさがった時刻
    			if ($this->ent[$k]->s_t == 0)   // 窓口のサービス終了時刻
    				$this->ent[$k]->end_time = $this->p_time + Exp_b($this->ent[$k]->mean);
    			else
    				$this->ent[$k]->end_time = $this->p_time + $this->ent[$k]->mean;
    		}
    	}
    	
    	/**********************************/
    	/* サービス終了時の処理           */
    	/*      kk : サービス終了窓口番号 */
    	/**********************************/
    	function Service($kk)
    	{
    	/*
    	          時間の設定
    	*/
    		$this->p_time = $this->ent[$kk]->end_time;   // 現在時刻
    		$this->ent[$kk]->end_time = -1.0;   // サービス終了時間
    	/*
    	          システムの外へ出る場合
    	*/
    		if ($this->ent[$kk]->to == 0) {
    	/*
    	               系内客数の処理
    	*/
    			$this->c_now_c += count($this->cus) * ($this->p_time - $this->now_c_t);   // 系内客数にその数が継続した時間を乗じた値の累計
    			$this->now_c_t  = $this->p_time;   // 現在の系内客数になった時刻
    	/*
    	               滞在時間の処理
    	*/
    			$it = $this->cus['no'.strval($this->ent[$kk]->service)];   // サービス中の客
    			$x1 = $this->p_time - $it->time;
    			$this->c_sys += $x1;   // 滞在時間の累計
    			if ($x1 > $this->max_sys)
    				$this->max_sys = $x1;   // 最大滞在時間
    			unset($this->cus['no'.strval($this->ent[$kk]->service)]);   // 客の削除(系内客数)
    		}
    	/*
    	          他の窓口処理へ入る場合の処理
    	*/
    		else {
    			$k1 = $this->ent[$kk]->out_n;
    			$this->que[$k1]->nc++;
    			$sw = 1;
    			$k2 = 0;
    			if (count($this->que[$k1]->que) == 0) {
    				for ($i1 = 0; $i1 < $this->que[$k1]->m; $i1++) {
    					$k2 = $this->que[$k1]->out_n[$i1];   // 窓口
    					if ($this->ent[$k2]->service == 0) {
    						$sw = 0;
    						break;
    					}
    				}
    			}
    	/*
    	               待ち行列がある場合
    	*/
    			if ($sw > 0) {
    				$this->que[$k1]->c_ql += count($this->que[$k1]->que) * ($this->p_time - $this->que[$k1]->ql_t);   // 待ち行列長にその長さが継続した時間を乗じた値の累計
    				array_push($this->que[$k1]->que, $this->ent[$kk]->service);   // 客の登録(待ち行列)
    				$this->que[$k1]->ql_t = $this->p_time;   // 現在の待ち行列長になった時刻
    				if (count($this->que[$k1]->que) > $this->que[$k1]->max_q_l)
    					$this->que[$k1]->max_q_l = count($this->que[$k1]->que);   // 最大待ち行列長
    				$it = $this->cus['no'.strval($this->ent[$kk]->service)];
    				$it->state1 = 0;   // 客の状態変更(待ち行列)
    				$it->state2 = $this->ent[$kk]->out_n;   // 客の状態変更(待ち行列番号)
    			}
    	/*
    	               すぐサービスをうけられる場合
    	*/
    			else {
    				$this->ent[$k2]->service = $this->ent[$kk]->service;   // サービスを受けている客番号
    				$this->ent[$k2]->busy_t  = $this->p_time;   // 窓口がふさがった時刻
    				if ($this->ent[$k2]->s_t == 0)   // 窓口のサービス終了時刻
    					$this->ent[$k2]->end_time = $this->p_time + Exp_b($this->ent[$k2]->mean);
    				else
    					$this->ent[$k2]->end_time = $this->p_time + $this->ent[$k2]->mean;
    			}
    		}
    	/*
    	          窓口使用時間の処理
    	*/
    		$this->ent[$kk]->service  = 0;   // 窓口を空き状態にする
    		$this->ent[$kk]->c_busy  += ($this->p_time - $this->ent[$kk]->busy_t);   // 窓口がふさがっている時間の累計
    	/*
    	          この窓口に対する待ち行列がある場合
    	*/
    		$k3 = $this->ent[$kk]->in_n;
    		if (count($this->que[$k3]->que) > 0) {
    			$this->que[$k3]->c_ql += count($this->que[$k3]->que) * ($this->p_time - $this->que[$k3]->ql_t);   // 待ち行列長にその長さが継続した時間を乗じた値の累計
    			$n = array_shift($this->que[$k3]->que);   // 待ち行列の先頭にいる客
    			$this->que[$k3]->ql_t = $this->p_time;   // 現在の待ち行列長になった時刻
    			$it = $this->cus['no'.$n];
    			$x1 = $this->p_time - $it->time;
    			$this->que[$k3]->c_wt += $x1;   // 待ち時間の累計
    			if ($x1 > $this->que[$k3]->max_wt)
    				$this->que[$k3]->max_wt = $x1;   // 最大待ち時間
    			for ($i1 = 0; $i1 < $this->que[$k3]->m; $i1++) {
    				$k4 = $this->que[$k3]->out_n[$i1];   // 窓口
    				if ($this->ent[$k4]->service == 0) {
    					$this->ent[$k4]->service = $n;   // 窓口の客番号
    					$this->ent[$k4]->busy_t  = $this->p_time;   // 窓口がふさがった時刻
    					if ($this->ent[$k4]->s_t == 0)   // 窓口のサービス終了時刻
    						$this->ent[$k4]->end_time = $this->p_time + Exp_b($this->ent[$k4]->mean);
    					else
    						$this->ent[$k4]->end_time = $this->p_time + $this->ent[$k4]->mean;
    					$it->state1 = 1;   // 客の状態変更(サービス中)
    					$it->state2 = $k4;   // 客の状態変更(窓口番号)
    					break;
    				}
    			}
    		}
    	}
    	
    	/**************************/
    	/* 統計量の計算と最終出力 */
    	/**************************/
    	function Output()
    	{
    						// System
    		printf("全客数 %d", $this->nc);
    		printf(" 最大系内客数 %d 最大滞在時間 %.3f\n", $this->max_c, $this->max_sys);
    		printf("平均系内客数 %.3f", $this->c_now_c / $this->p_time);
    		printf(" 平均滞在時間 %.3f", $this->c_sys / $this->nc);
    		printf(" 終了時間 %.3f\n", $this->p_time);
    						// Entity
    		for ($i1 = 0; $i1 < count($this->ent); $i1++) {
    			$e = $this->ent[$i1];
    			print("Entity ".$e->name);
    			printf(" 稼働率 %.3f\n", $e->c_busy / $this->p_time);
    		}
    						// Queue
    		for ($i1 = 0; $i1 < count($this->que); $i1++) {
    			$q = $this->que[$i1];
    			print("Queue ".$q->name);
    			printf(" 客数 %d", $q->nc);
    			printf("   最大待ち行列長 %d", $q->max_q_l);
    			printf("   最大待ち時間 %.3f\n", $q->max_wt);
    			printf("      平均待ち行列長 %.3f", $q->c_ql / $this->p_time);
    			printf("   平均待ち時間 %.3f\n", $q->c_wt / $q->nc);
    		}
    	}
    }
    	
    /****************/
    /* main program */
    /****************/
    					// 入り口
    	printf("入り口(Inlet)の数は? ");
    	fscanf(STDIN, "%d", $n_i);
    	$inl = array();
    	for ($i1 = 0; $i1 < $n_i; $i1++) {
    		printf("%d 番目の入り口(Inlet)\n", $i1+1);
    		printf("     名前は? ");
    		fscanf(STDIN, "%s", $name1);
    		$que = array();
    		printf("     到着分布(=0:指数分布,=1:一定時間間隔,<0:指定,客数の負値)? ");
    		fscanf(STDIN, "%d", $n);
    		if ($n == 0) {
    			printf("          到着時間間隔の平均値は? ");
    			fscanf(STDIN, "%lf", $m_a);
    		}
    		else if ($n == 1) {
    			printf("          到着時間間隔は? ");
    			fscanf(STDIN, "%lf", $m_a);
    		}
    		else {
    			for ($i2 = 0; $i2 < -$n; $i2++) {
    				printf("          到着時間は? ");
    				fscanf(STDIN, "%lf", $x);
    				array_push($que, $x);
    			}
    		}
    		printf("     並ぶ待ち行列の名前は? ");
    		fscanf(STDIN, "%s", $name2);
    		$inl_e = new Inlet($name1, $n, $m_a, $que, $name2);
    		array_push($inl, $inl_e);
    	}
    					// 待ち行列
    	printf("待ち行列(Queue)の数は? ");
    	fscanf(STDIN, "%d", $n_q);
    	$que = array();
    	for ($i1 = 0; $i1 < $n_q; $i1++) {
    		printf("%d 番目の待ち行列(Queue)\n", $i1+1);
    		printf("     名前は? ");
    		fscanf(STDIN, "%s", $name1);
    		printf("     入り口(0),または,窓口(n>0,窓口の数)から? ");
    		fscanf(STDIN, "%d", $n);
    		$in = array();
    		if ($n == 0) {
    			printf("          入り口の名前は? ");
    			fscanf(STDIN, "%s", $name2);
    			array_push($in, $name2);
    		}
    		else {
    			for ($i2 = 0; $i2 < $n; $i2++) {
    				printf("          %d 番目の窓口の名前は? ", $i2+1);
    				fscanf(STDIN, "%s", $name3);
    				array_push($in, $name3);
    			}
    		}
    		printf("     処理する窓口の数は? ");
    		fscanf(STDIN, "%d", $m);
    		$out = array();
    		for ($i2 = 0; $i2 < $m; $i2++) {
    			printf("          %d 番目の窓口の名前は? ", $i2+1);
    			fscanf(STDIN, "%s", $name4);
    			array_push($out, $name4);
    		}
    		$que_e = new Queue($name1, $n, $in, $m, $out);
    		array_push($que, $que_e);
    	}
    					// 窓口
    	printf("窓口(Entity)の数は? ");
    	fscanf(STDIN, "%d", $n_e);
    	$ent = array();
    	for ($i1 = 0; $i1 < $n_e; $i1++) {
    		printf("%d 番目の窓口(Entity)\n", $i1+1);
    		printf("     名前は? ");
    		fscanf(STDIN, "%s", $name1);
    		printf("     サービス分布(=0:指数分布,=1:一定時間)? ");
    		fscanf(STDIN, "%d", $s_t);
    		if ($s_t == 0) {
    			printf("          サービス時間の平均値は? ");
    			fscanf(STDIN, "%lf", $m_s);
    		}
    		else {
    			printf("          サービス時間は? ");
    			fscanf(STDIN, "%lf", $m_s);
    		}
    		printf("     待ち行列(入力)の名前は? ");
    		fscanf(STDIN, "%s", $name2);
    		printf("     終了後,外部(0),または,待ち行列(1)? ");
    		fscanf(STDIN, "%d", $sw);
    		$name3 = "";
    		if ($sw > 0) {
    			printf("          待ち行列(出力)の名前は? ");
    			fscanf(STDIN, "%s", $name3);
    		}
    		$ent_e = new Entity($name1, $s_t, $m_s, $name2, $sw, $name3);
    		array_push($ent, $ent_e);
    	}
    					// 全体の制御を行うクラス
    	printf("シミュレーション終了時間? ");
    	fscanf(STDIN, "%lf", $end);
    
    	$base = new Q_base($inl, $que, $ent, $end);   // 全体の制御を行うクラス
    					// 実行
    	$base->Control();
    					// 出力
    	$base->Output();
    
    /*
    ------------入力例(簡単な場合)-----------
    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
    */
    
    ?>
    			

  5. Ruby

    #############################
    # 複雑な待ち行列問題
    #      coded by Y.Suganuma
    #############################
    
    #####################
    # クラスInletの定義
    #####################
    
    class Inlet
    
    	###########################################################
    	# コンストラクタ
    	#      name1 : 入り口名
    	#      a_t1   # = -n : 到着する客の人数を負の値にしたもの
    	#             # =0 : 指数分布
    	#             # =1 : 一定時間間隔
    	#      m_a: 到着時間間隔またはその平均
    	#      que1 : 客の到着時刻リスト
    	#      name2 : 待ち行列名
    	###########################################################
    
    	def initialize(name1, a_t1, m_a, que1, name2)
    	
    		@_name = name1   # 入り口名
    		@_out  = name2   # 待ち行列名
    		@_a_t  = a_t1   # = -n : 到着する客の人数を負の値にしたもの
    		                # =0 : 指数分布
    		                # =1 : 一定時間間隔
    		@_mean = m_a   # 到着時間間隔またはその平均
    		@_que  = que1   # 客の到着時刻リスト
    		if @_a_t == 0
    			@_arrive_time = -@_mean * Math.log(rand(0))   # 客の到着時刻(負:客がない)
    		elsif @_a_t == 1
    			@_arrive_time = 0
    		else
    			@_arrive_time = @_que.delete_at(0)
    		end
    		@_out_n = 0   # 待ち行列番号(Q_baseのコンストラクタで設定)
    	end
    
    	attr_accessor("_out_n", "_out", "_name", "_arrive_time", "_a_t", "_mean", "_que")
    end
    
    #####################
    # クラスQueueの定義
    #####################
    
    class Queue
    
    	#############################################
    	# コンストラクタ
    	#      name1 : 待ち行列名
    	#      n1 : =0 : 入り口から入る
    	#           >0 : 複数の窓口から入る(窓口数)
    	#      in1 : 入り口名,または,窓口名
    	#      m1 : 処理する窓口数
    	#      out1 : 窓口名
    	#############################################
    
    	def initialize(name1, n1, in1, m1, out1)
    	
    		@_name    = name1   # 待ち行列名
    		@_n       = n1   # =0 : 入り口から入る
    		                 # >0 : 複数の窓口から入る(窓口数)
    		@_inn     = in1   # 入り口名,または,窓口名(入り口)
    		@_m       = m1   # 処理する窓口数
    		@_out     = out1   # 窓口名(出口)
    		@_nc      = 0   # 待ち行列への到着客数カウンタ
    		@_max_q_l = 0   # 最大待ち行列長
    		@_c_ql    = 0.0   # 待ち行列長にその長さが継続した時間を乗じた値の累計
    		@_ql_t    = 0.0   # 現在の待ち行列長になった時間
    		@_max_wt  = 0.0   # 最大待ち時間
    		@_c_wt    = 0.0   # 待ち時間の累計
    		@_in_n    = Array.new()   # 入り口番号,または,窓口番号(Q_baseのコンストラクタで設定)
    		@_out_n   = Array.new()   # 窓口番号(Q_baseのコンストラクタで設定)
    		@_que     = Array.new()   # 待ち行列
    	end
    
    	attr_accessor("_name", "_n", "_m", "_inn", "_in_n", "_out", "_out_n", "_nc", "_c_ql", "_que", "_ql_t", "_max_q_l", "_c_wt", "_max_wt")
    end
    
    ######################
    # クラスEntityの定義
    ######################
    
    class Entity
    
    	########################################
    	# コンストラクタ
    	#      name1 : 窓口名
    	#      s_t1   # =0 : 指数分布
    	#             # =1 : 一定時間
    	#      m_s:サービス時間またはその平均
    	#      name2 : 待ち行列(入力)の名前
    	#      sw : =0 : システムの外に出る
    	#           =1 : 待ち行列に入る
    	#      name3 : 待ち行列(出力)の名前
    	########################################
    
    	def initialize(name1, s_t1, m_s, name2, sw, name3)
    	
    		@_name = name1   # 窓口名
    		@_to   = sw   # =0 : システムの外に出る
    		              # =1 : 待ち行列に入る
    		@_inn  = name2   # 待ち行列(入力)の名前
    		if @_to > 0
    			@_out = name3   # 待ち行列(出力)の名前
    		end
    		@_end_time = -1.0   # サービス終了時刻(負:何も処理していない)
    		@_s_t      = s_t1   # =0 : 指数分布
    		                    # =1 : 一定時間
    		@_mean     = m_s   # 平均サービス時間
    		@_service  = 0   # サービス中の客番号(0のときは無し)
    		@_busy_t   = -1.0   # 窓口がふさがった時刻
    		@_c_busy   = 0.0   # 窓口がふさがっている時間の累計
    		@_in_n     = -1   # 待ち行列(入力)番号(Q_baseのコンストラクタで設定)
    		@_out_n    = -1   # 待ち行列(出力)番号(Q_baseのコンストラクタで設定)
    	end
    
    	attr_accessor("_service", "_name", "_inn", "_in_n", "_to", "_out", "_out_n", "_end_time", "_busy_t", "_s_t", "_c_busy", "_mean")
    end
    
    ########################
    # クラスCustomerの定義
    ########################
    
    class Customer
    	
    	#####################
    	# コンストラクタ
    	#      s1,s2 : 状態
    	#      t : 到着時刻
    	#####################
    
    	def initialize(s1, s2, t)
    	
    		@_time   = t   # 到着時刻
    		@_state1 = s1   # 客の状態1
    		                #   =0 : 待ち行列に入っている
    		                #   =1 : サービスを受けている
    		@_state2 = s2   # 客の状態2(待ち行列番号,または,窓口番号)
    	end
    
    	attr_accessor("_state1", "_state2", "_time")
    end
    
    #######################
    # クラスQ_baseの定義
    #######################
    
    class Q_base
    
    	########################################
    	# コンストラクタ
    	#      v_i : Inletオブジェクトリスト
    	#      v_q : Queueオブジェクトリスト
    	#      v_e : Entityオブジェクトリスト
    	#      e : シミュレーション終了時刻
    	########################################
    
    	def initialize(v_i, v_q, v_e, e)
    
    		print("\n")
    				# 接続関係のチェック
    		@_inl = v_i   # Inletオブジェクトリスト
    		@_que = v_q   # Queueオブジェクトリスト
    		@_ent = v_e   # Entityオブジェクトリスト
    						# Inlet
    		for i1 in 0 ... @_inl.length-1
    			for i2 in i1+1 ... @_inl.length
    				if @_inl[i1]._name == @_inl[i2]._name
    					print("***error 同じ名前の入り口があります " + @_inl[i1]._name + "\n")
    				end
    			end
    		end
    
    		for i1 in 0 ... @_inl.length
    			k = -1
    			for i2 in 0 ... @_que.length
    				if @_inl[i1]._out == @_que[i2]._name
    					k = i2
    					break
    				end
    			end
    			if k >= 0
    				@_inl[i1]._out_n = k
    			else
    				print("***error 入り口から入る待ち行列名が不適当です " + @_inl[i1]._out + "\n")
    			end
    		end
    						# Queue
    		for i1 in 0 ... @_que.length-1
    			for i2 in i1+1 ... @_que.length
    				if @_que[i1]._name == @_que[i2]._name
    					print("***error 同じ名前の待ち行列があります " + @_que[i1]._name + "\n")
    				end
    			end
    		end
    
    		for i1 in 0 ... @_que.length
    			if @_que[i1]._n == 0
    				k = -1
    				for i2 in 0 ... @_inl.length
    					if @_que[i1]._inn[0] == @_inl[i2]._name
    						k = i2
    						break
    					end
    				end
    				if k >= 0
    					@_que[i1]._in_n.push(k)
    				else
    					print("***error 待ち行列に入る入り口名が不適当です " + @_que[i1]._inn[0] + "\n")
    				end
    			else
    				for i2 in 0 ... @_que[i1]._n
    					k = -1
    					for i3 in 0 ... @_ent.length
    						if @_que[i1]._inn[i2] == @_ent[i3]._name
    							k = i3
    							break
    						end
    					end
    					if k >= 0
    						@_que[i1]._in_n.push(k)
    					else
    						print("***error 待ち行列に入る窓口名が不適当です " + @_que[i1]._inn[i2] + "\n")
    					end
    				end
    			end
    			for i2 in 0 ... @_que[i1]._m
    				k = -1
    				for i3 in 0 ... @_ent.length
    					if @_que[i1]._out[i2] == @_ent[i3]._name
    						k = i3
    						break
    					end
    				end
    				if k >= 0
    					@_que[i1]._out_n.push(k)
    				else
    					print("***error 待ち行列を処理する窓口名が不適当です " + @_que[i1]._out[i2])
    				end
    			end
    		end
    						# Entity
    		for i1 in 0 ... @_ent.length-1
    			k = -1
    			for i2 in i1+1 ... @_ent.length
    				if @_ent[i1]._name == @_ent[i2]._name
    					print("***error 同じ名前の窓口があります " + @_ent[i1]._name + "\n")
    				end
    			end
    		end
    
    		for i1 in 0 ... @_ent.length
    			k = -1
    			for i2 in 0 ... @_que.length
    				if @_ent[i1]._inn == @_que[i2]._name
    					k = i2
    					break
    				end
    			end
    			if k >= 0
    				@_ent[i1]._in_n = k
    			else
    				print("***error 窓口に入る待ち行列名が不適当です " + @_ent[i1]._inn + "\n")
    			end
    			if @_ent[i1]._to > 0
    				k = -1
    				for i2 in 0 ... @_que.length
    					if @_ent[i1]._out == @_que[i2]._name
    						k = i2
    						break
    					end
    				end
    				if k >= 0
    					@_ent[i1]._out_n = k
    				else
    					print("***error 窓口の出口にある待ち行列名が不適当です " + @_ent[i1]._out)
    				end
    			end
    		end
    				# 初期設定
    		@_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   # シミュレーション終了時間
    		@_cus     = Hash.new()   # 系内にいる客のリスト
    				# 乱数の初期設定
    		srand()
    	end
    	
    	#############
    	# 全体の制御
    	#############
    
    	def Control()
    	
    		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])   # サービスの終了
    				end
    			end
    		end
    	end
    	
    	#############################################
    	# 次の処理の決定
    	#      sw[0] : =-1 : シミュレーションの終了
    	#              =0  : 客の到着処理
    	#              =1  : 窓口のサービス終了
    	#        [1] : 入り口番号 or 窓口番号
    	#############################################
    
    	def Next(sw)
    	
    		tm    = @_end   # 次の処理時刻
    		sw[0] = -1
    						# 次の客の到着時刻
    		for i1 in 0 ... @_inl.length
    			x = @_inl[i1]
    			if x._arrive_time >= 0.0 and x._arrive_time < tm
    				sw[0] = 0
    				sw[1] = i1
    				tm    = x._arrive_time
    			end
    		end
    						# サービス終了時刻
    		for i1 in 0 ... @_ent.length
    			x = @_ent[i1]
    			if x._service > 0 and x._end_time <= tm
    				sw[0] = 1
    				sw[1] = i1
    				tm    = x._end_time
    			end
    		end
    	
    		if sw[0] < 0
    			@_end = @_p_time
    		end
    	end
    	
    	##################################
    	# 終了処理
    	#      return : =-1 : 終了前処理
    	#               =-2 : 実際の終了
    	##################################
    
    	def End_o_s()
    	
    		sw       = -2
    		@_p_time = @_end   # 現在時刻
    	
    		for i1 in 0 ... @_ent.length
    			x = @_ent[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のサービス終了時刻
    					end
    				end
    			end
    		end
    	
    		return sw
    	end
    	
    	########################
    	# 客の到着処理
    	#      kk : 入り口番号
    	########################
    
    	def Arrive(kk)
    				# 客数の増加と次の客の到着時刻の設定
    		@_nc      += 1   # 到着客数カウンタ
    		@_p_time   = @_inl[kk]._arrive_time   # 現在時刻
    		if @_inl[kk]._a_t == 0   # 次の客の到着時刻
    			@_inl[kk]._arrive_time = @_p_time - @_inl[kk]._mean * Math.log(rand(0))
    		elsif @_inl[kk]._a_t == 1
    			@_inl[kk]._arrive_time = @_p_time + @_inl[kk]._mean   
    		else
    			if (@_inl[kk]._que).length < 1
    				@_inl[kk]._arrive_time = -1.0
    			else
    				@_inl[kk]._arrive_time = @_inl[kk]._que.delete_at(0)
    			end
    		end
    		if @_inl[kk]._arrive_time >= @_end
    			@_inl[kk]._arrive_time = -1.0
    		end
    				# 系内客数の処理
    		@_c_now_c += @_cus.length * (@_p_time - @_now_c_t)   # 系内客数にその数が継続した時間を乗じた値の累計
    		@_now_c_t  = @_p_time   # 現在の系内客数になった時刻
    		if @_cus.length+1 > @_max_c
    			@_max_c = @_cus.length + 1   # 最大系内客数
    		end
    				# 空いている窓口を探す
    		k1             = @_inl[kk]._out_n
    		@_que[k1]._nc += 1
    		k              = -1
    		for i1 in 0 ... @_que[k1]._m
    			k2 = @_que[k1]._out_n[i1]   # 処理窓口
    			if @_ent[k2]._service == 0
    				k = k2
    				break
    			end
    		end
    				# 窓口に空きがない場合
    		if k < 0
    			ct_p             = Customer.new(0, k1, @_p_time)
    			@_cus[@_nc]      = ct_p   # 客の登録(系内客数)
    			@_que[k1]._c_ql += (@_que[k1]._que).length * (@_p_time - @_que[k1]._ql_t)   # 待ち行列長にその長さが継続した時間を乗じた値の累計
    			@_que[k1]._que.push(@_nc)   # 客の登録(待ち行列)
    			@_que[k1]._ql_t = @_p_time   # 現在の待ち行列長になった時刻
    			if (@_que[k1]._que).length > @_que[k1]._max_q_l
    				@_que[k1]._max_q_l = (@_que[k1]._que).length   # 最大待ち行列長
    			end
    				# すぐサービスをうけられる場合
    		else
    			ct_p              = Customer.new(1, k, @_p_time)
    			@_cus[@_nc]       = ct_p   # 客の登録(系内客数)
    			@_ent[k]._service = @_nc   # サービスを受けている客番号
    			@_ent[k]._busy_t  = @_p_time   # 窓口がふさがった時刻
    			if @_ent[k]._s_t == 0   # 窓口のサービス終了時刻
    				@_ent[k]._end_time = @_p_time - @_ent[k]._mean * Math.log(rand(0))
    			else
    				@_ent[k]._end_time = @_p_time + @_ent[k]._mean
    			end
    		end
    	end
    	
    	###################################
    	# サービス終了時の処理
    	#      kk : サービス終了窓口番号
    	###################################
    
    	def Service(kk)
    				# 時間の設定
    		@_p_time            = @_ent[kk]._end_time   # 現在時刻
    		@_ent[kk]._end_time = -1.0   # サービス終了時間
    				# システムの外へ出る場合
    		if @_ent[kk]._to == 0
    				# 系内客数の処理
    			@_c_now_c += @_cus.length * (@_p_time - @_now_c_t)   # 系内客数にその数が継続した時間を乗じた値の累計
    			@_now_c_t  = @_p_time   # 現在の系内客数になった時刻
    				# 滞在時間の処理
    			it = @_cus[@_ent[kk]._service]   # サービス中の客
    			x1 = @_p_time - it._time
    			@_c_sys += x1   # 滞在時間の累計
    			if x1 > @_max_sys
    				@_max_sys = x1   # 最大滞在時間
    			end
    			@_cus.delete(@_ent[kk]._service)   # 客の削除(系内客数)
    				# 他の窓口処理へ入る場合の処理
    		else
    			k1             = @_ent[kk]._out_n
    			@_que[k1]._nc += 1
    			sw             = 1
    			k2             = 0
    			if (@_que[k1]._que).length == 0
    				for i1 in 0 ... @_que[k1]._m
    					k2 = @_que[k1]._out_n[i1]   # 窓口
    					if @_ent[k2]._service == 0
    						sw = 0
    						break
    					end
    				end
    			end
    				# 待ち行列がある場合
    			if sw > 0
    				@_que[k1]._c_ql += (@_que[k1]._que).length * (@_p_time - @_que[k1]._ql_t)   # 待ち行列長にその長さが継続した時間を乗じた値の累計
    				@_que[k1]._que.push(@_ent[kk]._service)   # 客の登録(待ち行列)
    				@_que[k1]._ql_t = @_p_time   # 現在の待ち行列長になった時刻
    				if (@_que[k1]._que).length > @_que[k1]._max_q_l
    					@_que[k1]._max_q_l = (@_que[k1]._que).length   # 最大待ち行列長
    				end
    				it         = @_cus[@_ent[kk]._service]
    				it._state1 = 0   # 客の状態変更(待ち行列)
    				it._state2 = @_ent[kk]._out_n   # 客の状態変更(待ち行列番号)
    				# すぐサービスをうけられる場合
    			else
    				@_ent[k2]._service = @_ent[kk]._service   # サービスを受けている客番号
    				@_ent[k2]._busy_t  = @_p_time   # 窓口がふさがった時刻
    				if @_ent[k2]._s_t == 0   # 窓口のサービス終了時刻
    					@_ent[k2]._end_time = @_p_time - @_ent[k2]._mean * Math.log(rand(0))
    				else
    					@_ent[k2]._end_time = @_p_time + @_ent[k2]._mean
    				end
    			end
    		end
    				# 窓口使用時間の処理
    		@_ent[kk]._service  = 0   # 窓口を空き状態にする
    		@_ent[kk]._c_busy  += (@_p_time - @_ent[kk]._busy_t)   # 窓口がふさがっている時間の累計
    				# この窓口に対する待ち行列がある場合
    		k3 = @_ent[kk]._in_n
    		if (@_que[k3]._que).length > 0
    			@_que[k3]._c_ql += (@_que[k3]._que).length * (@_p_time - @_que[k3]._ql_t)   # 待ち行列長にその長さが継続した時間を乗じた値の累計
    			n                = @_que[k3]._que.delete_at(0)   # 待ち行列の先頭にいる客
    			@_que[k3]._ql_t  = @_p_time   # 現在の待ち行列長になった時刻
    			x1               = @_p_time - @_cus[n]._time
    			@_que[k3]._c_wt += x1   # 待ち時間の累計
    			if x1 > @_que[k3]._max_wt
    				@_que[k3]._max_wt = x1   # 最大待ち時間
    			end
    			for i1 in 0 ... @_que[k3]._m
    				k4 = @_que[k3]._out_n[i1]   # 窓口
    				if @_ent[k4]._service == 0
    					@_ent[k4]._service = n   # 窓口の客番号
    					@_ent[k4]._busy_t  = @_p_time   # 窓口がふさがった時刻
    					if @_ent[k4]._s_t == 0   # 窓口のサービス終了時刻
    						@_ent[k4]._end_time = @_p_time - @_ent[k4]._mean * Math.log(rand(0))
    					else
    						@_ent[k4]._end_time = @_p_time + @_ent[k4]._mean
    					end
    					@_cus[n]._state1 = 1   # 客の状態変更(サービス中)
    					@_cus[n]._state2 = k4   # 客の状態変更(窓口番号)
    					break
    				end
    			end
    		end
    	end
    	
    	##########################
    	# 統計量の計算と最終出力
    	##########################
    
    	def Output()
    						# System
    		printf("全客数 %d", @_nc)
    		printf(" 最大系内客数 %d 最大滞在時間 %.3f\n", @_max_c, @_max_sys)
    		printf("平均系内客数 %.3f", (@_c_now_c / @_p_time))
    		printf(" 平均滞在時間 %.3f", (@_c_sys / @_nc))
    		printf(" 終了時間 %.3f\n", @_p_time)
    						# Entity
    		for i1 in 0 ... @_ent.length
    			e = @_ent[i1]
    			printf("Entity " + e._name)
    			printf(" 稼働率 %.3f\n", (e._c_busy / @_p_time))
    		end
    						# Queue
    		for i1 in 0 ... @_que.length
    			q = @_que[i1]
    			printf("Queue " + q._name)
    			printf(" 客数 %d", q._nc)
    			printf("   最大待ち行列長 %d", q._max_q_l)
    			printf("   最大待ち時間 %.3f\n", q._max_wt)
    			printf("      平均待ち行列長 %.3f", (q._c_ql / @_p_time))
    			printf("   平均待ち時間 %.3f\n", (q._c_wt / q._nc))
    		end
    	end
    end
    
    					# 入り口
    print("入り口(Inlet)の数は? ")
    n_i = Integer(gets())
    inl = Array.new()
    for i1 in 0 ... n_i
    	print(String(i1+1) + " 番目の入り口(Inlet)\n")
    	print("     名前は? ")
    	name1 = gets().strip()
    	qq    = Array.new()
    	print("     到着分布(=0:指数分布,=1:一定時間間隔,<0:指定,客数の負値)? ")
    	n = Integer(gets())
    	if n == 0
    		print("          到着時間間隔の平均値は? ")
    		m_a = Float(gets())
    	elsif n == 1
    		print("          到着時間間隔は? ")
    		m_a = Float(gets())
    	else
    		for i2 in range(0, -n)
    			print("          到着時間は? ")
    			x = Float(gets())
    			qq.push(x)
    		end
    	end
    	print("     並ぶ待ち行列の名前は? ")
    	name2 = gets().strip()
    	inl_e = Inlet.new(name1, n, m_a, qq, name2)
    	inl.push(inl_e)
    end
    				# 待ち行列
    print("待ち行列(Queue)の数は? ")
    n_q = Integer(gets())
    que = Array.new()
    for i1 in 0 ... n_q
    	print(String(i1+1) + " 番目の待ち行列(Queue)\n")
    	print("     名前は? ")
    	name1 = gets().strip()
    	print("     入り口(0),または,窓口(n>0,窓口の数)から? ")
    	n   = Integer(gets())
    	inn = Array.new()
    	if n == 0
    		print("          入り口の名前は? ")
    		name2 = gets().strip()
    		inn.push(name2)
    	else
    		for i2 in 0 ... n
    			print("          " + String(i2+1) + " 番目の窓口の名前は? ")
    			name3 = gets().strip()
    			inn.push(name3)
    		end
    	end
    	print("     処理する窓口の数は? ")
    	m   = Integer(gets())
    	out = Array.new()
    	for i2 in 0 ... m
    		print("          " +String(i2+1) + " 番目の窓口の名前は? ")
    		name4 = gets().strip()
    		out.push(name4)
    	end
    	que_e = Queue.new(name1, n, inn, m, out)
    	que.push(que_e)
    end
    				# 窓口
    print("窓口(Entity)の数は? ")
    n_e = Integer(gets())
    ent = Array.new()
    for i1 in 0 ... n_e
    	print(String(i1+1) + " 番目の窓口(Entity)\n")
    	print("     名前は? ")
    	name1 = gets().strip()
    	print("     サービス分布(=0:指数分布,=1:一定時間)? ")
    	s_t = Integer(gets())
    	if s_t == 0
    		print("          サービス時間の平均値は? ")
    		m_s = Float(gets())
    	else
    		print("          サービス時間は? ")
    		m_s = Float(gets())
    	end
    	print("     待ち行列(入力)の名前は? ")
    	name2 = gets().strip()
    	print("     終了後,外部(0),または,待ち行列(1)? ")
    	sw    = Integer(gets())
    	name3 = ""
    	if sw > 0
    		print("          待ち行列(出力)の名前は? ")
    		name3 = gets().strip()
    	end
    	ent_e = Entity.new(name1, s_t, m_s, name2, sw, name3)
    	ent.push(ent_e)
    end
    				# 全体の制御を行うクラス
    print("シミュレーション終了時間? ")
    stp  = Float(gets())
    base = Q_base.new(inl, que, ent, stp)   # 全体の制御を行うクラス
    				# 実行
    base.Control()
    				# 出力
    base.Output()
    
    =begin
    ------------入力例(簡単な場合)-----------
    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
    =end
    			

  6. Python

    # -*- coding: UTF-8 -*-
    import numpy as np
    import sys
    from math import *
    from random import *
    
    #####################
    # クラスInletの定義
    #####################
    
    class Inlet :
    
    	###########################################################
    	# コンストラクタ
    	#      name1 : 入り口名
    	#      a_t1   # = -n : 到着する客の人数を負の値にしたもの
    	#             # =0 : 指数分布
    	#             # =1 : 一定時間間隔
    	#      m_a: 到着時間間隔またはその平均
    	#      que1 : 客の到着時刻リスト
    	#      name2 : 待ち行列名
    	###########################################################
    
    	def __init__(self, name1, a_t1, m_a, que1, name2) :
    	
    		self.name = name1   # 入り口名
    		self.out  = name2   # 待ち行列名
    		self.a_t  = a_t1   # = -n : 到着する客の人数を負の値にしたもの
    		                   # =0 : 指数分布
    		                   # =1 : 一定時間間隔
    		self.mean = m_a   # 到着時間間隔またはその平均
    		self.que  = que1   # 客の到着時刻リスト
    		if self.a_t == 0 :
    			self.arrive_time = expovariate(1.0 / self.mean)   # 客の到着時刻(負:客がない)
    		elif self.a_t == 1 :
    			self.arrive_time = 0
    		else :
    			self.arrive_time = self.que.pop(0)
    		self.out_n = 0   # 待ち行列番号(Q_baseのコンストラクタで設定)
    
    #####################
    # クラスQueueの定義
    #####################
    
    class Queue :
    
    	#############################################
    	# コンストラクタ
    	#      name1 : 待ち行列名
    	#      n1 : =0 : 入り口から入る
    	#           >0 : 複数の窓口から入る(窓口数)
    	#      in1 : 入り口名,または,窓口名
    	#      m1 : 処理する窓口数
    	#      out1 : 窓口名
    	#############################################
    
    	def __init__(self, name1, n1, in1, m1, out1) :
    	
    		self.name    = name1   # 待ち行列名
    		self.n       = n1   # =0 : 入り口から入る
    		                    # >0 : 複数の窓口から入る(窓口数)
    		self.inn     = in1   # 入り口名,または,窓口名(入り口)
    		self.m       = m1   # 処理する窓口数
    		self.out     = out1   # 窓口名(出口)
    		self.nc      = 0   # 待ち行列への到着客数カウンタ
    		self.max_q_l = 0   # 最大待ち行列長
    		self.c_ql    = 0.0   # 待ち行列長にその長さが継続した時間を乗じた値の累計
    		self.ql_t    = 0.0   # 現在の待ち行列長になった時間
    		self.max_wt  = 0.0   # 最大待ち時間
    		self.c_wt    = 0.0   # 待ち時間の累計
    		self.in_n    = []   # 入り口番号,または,窓口番号(Q_baseのコンストラクタで設定)
    		self.out_n   = []   # 窓口番号(Q_baseのコンストラクタで設定)
    		self.que     = []   # 待ち行列
    
    ######################
    # クラスEntityの定義
    ######################
    
    class Entity :
    
    	########################################
    	# コンストラクタ
    	#      name1 : 窓口名
    	#      s_t1   # =0 : 指数分布
    	#             # =1 : 一定時間
    	#      m_s:サービス時間またはその平均
    	#      name2 : 待ち行列(入力)の名前
    	#      sw : =0 : システムの外に出る
    	#           =1 : 待ち行列に入る
    	#      name3 : 待ち行列(出力)の名前
    	########################################
    
    	def __init__(self, name1, s_t1, m_s, name2, sw, name3) :
    	
    		self.name = name1   # 窓口名
    		self.to   = sw   # =0 : システムの外に出る
    		                 # =1 : 待ち行列に入る
    		self.inn  = name2   # 待ち行列(入力)の名前
    		if self.to > 0 :
    			self.out = name3   # 待ち行列(出力)の名前
    		self.end_time = -1.0   # サービス終了時刻(負:何も処理していない)
    		self.s_t      = s_t1   # =0 : 指数分布
    		                       # =1 : 一定時間
    		self.mean     = m_s   # 平均サービス時間
    		self.service  = 0   # サービス中の客番号(0のときは無し)
    		self.busy_t   = -1.0   # 窓口がふさがった時刻
    		self.c_busy   = 0.0   # 窓口がふさがっている時間の累計
    		self.in_n     = -1   # 待ち行列(入力)番号(Q_baseのコンストラクタで設定)
    		self.out_n    = -1   # 待ち行列(出力)番号(Q_baseのコンストラクタで設定)
    
    ########################
    # クラスCustomerの定義
    ########################
    
    class Customer :
    	
    	#####################
    	# コンストラクタ
    	#      s1,s2 : 状態
    	#      t : 到着時刻
    	#####################
    
    	def __init__(self, s1, s2, t) :
    	
    		self.time   = t   # 到着時刻
    		self.state1 = s1   # 客の状態1
    		                   #   =0 : 待ち行列に入っている
    		                   #   =1 : サービスを受けている
    		self.state2 = s2   # 客の状態2(待ち行列番号,または,窓口番号)
    
    #######################
    # クラスQ_baseの定義
    #######################
    
    class Q_base :
    
    	########################################
    	# コンストラクタ
    	#      v_i : Inletオブジェクトリスト
    	#      v_q : Queueオブジェクトリスト
    	#      v_e : Entityオブジェクトリスト
    	#      e : シミュレーション終了時刻
    	########################################
    
    	def __init__(self, v_i, v_q, v_e, e) :
    
    		print("")
    				# 接続関係のチェック
    		self.inl = v_i   # Inletオブジェクトリスト
    		self.que = v_q   # Queueオブジェクトリスト
    		self.ent = v_e   # Entityオブジェクトリスト
    						# Inlet
    		for i1 in range(0, len(self.inl)-1) :
    			for i2 in range(i1+1, len(self.inl)) :
    				if self.inl[i1].name == self.inl[i2].name :
    					print("***error 同じ名前の入り口があります " + self.inl[i1].name)
    
    		for i1 in range(0, len(self.inl)) :
    			k = -1
    			for i2 in range(0, len(self.que)) :
    				if self.inl[i1].out == self.que[i2].name :
    					k = i2
    					break
    			if k >= 0 :
    				self.inl[i1].out_n = k
    			else :
    				print("***error 入り口から入る待ち行列名が不適当です " + self.inl[i1].out)
    						# Queue
    		for i1 in range(0, len(self.que)-1) :
    			for i2 in range(i1+1, len(self.que)) :
    				if self.que[i1].name == self.que[i2].name :
    					print("***error 同じ名前の待ち行列があります " + self.que[i1].name)
    
    		for i1 in range(0, len(self.que)) :
    			if self.que[i1].n == 0 :
    				k = -1
    				for i2 in range(0, len(self.inl)) :
    					if self.que[i1].inn[0] == self.inl[i2].name :
    						k = i2
    						break
    				if k >= 0 :
    					self.que[i1].in_n.append(k)
    				else :
    					print("***error 待ち行列に入る入り口名が不適当です " + self.que[i1].inn[0])
    			else :
    				for i2 in range(0, self.que[i1].n) :
    					k = -1
    					for i3 in range(0, len(self.ent)) :
    						if self.que[i1].inn[i2] == self.ent[i3].name :
    							k = i3
    							break
    					if k >= 0 :
    						self.que[i1].in_n.append(k)
    					else :
    						print("***error 待ち行列に入る窓口名が不適当です " + self.que[i1].inn[i2])
    			for i2 in range(0, self.que[i1].m) :
    				k = -1
    				for i3 in range(0, len(self.ent)) :
    					if self.que[i1].out[i2] == self.ent[i3].name :
    						k = i3
    						break
    				if k >= 0 :
    					self.que[i1].out_n.append(k)
    				else :
    					print("***error 待ち行列を処理する窓口名が不適当です " + self.que[i1].out[i2])
    						# Entity
    		for i1 in range(0, len(self.ent)-1) :
    			k = -1
    			for i2 in range(i1+1, len(self.ent)) :
    				if self.ent[i1].name == self.ent[i2].name :
    					print("***error 同じ名前の窓口があります " + self.ent[i1].name)
    
    		for i1 in range(0, len(self.ent)) :
    			k = -1
    			for i2 in range(0, len(self.que)) :
    				if self.ent[i1].inn == self.que[i2].name :
    					k = i2
    					break
    			if k >= 0 :
    				self.ent[i1].in_n = k
    			else :
    				print("***error 窓口に入る待ち行列名が不適当です " + self.ent[i1].inn)
    			if self.ent[i1].to > 0 :
    				k = -1
    				for i2 in range(0, len(self.que)) :
    					if self.ent[i1].out == self.que[i2].name :
    						k = i2
    						break
    				if k >= 0 :
    					self.ent[i1].out_n = k
    				else :
    					print("***error 窓口の出口にある待ち行列名が不適当です " + self.ent[i1].out)
    				# 初期設定
    		self.p_time  = 0.0   # 現在時刻
    		self.max_c   = 0   # 最大系内客数
    		self.nc      = 0   # システムへの到着客数カウンタ
    		self.now_c_t = 0.0   # 現在の系内客数になった時間
    		self.c_now_c = 0.0   # 系内客数にその数が継続した時間を乗じた値の累計
    		self.c_sys   = 0.0   # 滞在時間の累計
    		self.max_sys = 0.0   # 最大滞在時間
    		self.end     = e   # シミュレーション終了時間
    		self.cus     = dict()   # 系内にいる客のリスト
    				# 乱数の初期設定
    		seed()
    	
    	#############
    	# 全体の制御
    	#############
    
    	def Control(self) :
    	
    		sw = np.zeros(2, np.int)
    
    		while sw[0] > -2 :
    			self.Next(sw)   # 次の処理の選択
    			if sw[0] == -1 :
    				sw[0] = self.End_o_s()   # シミュレーションの終了
    			else :
    				if sw[0] == 0 :
    					self.Arrive(sw[1])   # 客の到着処理
    				else :
    					self.Service(sw[1])   # サービスの終了
    	
    	#############################################
    	# 次の処理の決定
    	#      sw[0] : =-1 : シミュレーションの終了
    	#              =0  : 客の到着処理
    	#              =1  : 窓口のサービス終了
    	#        [1] : 入り口番号 or 窓口番号
    	#############################################
    
    	def Next(self, sw) :
    	
    		tm    = self.end   # 次の処理時刻
    		sw[0] = -1
    						# 次の客の到着時刻
    		for i1 in range(0, len(self.inl)) :
    			x = self.inl[i1]
    			if x.arrive_time >= 0.0 and x.arrive_time < tm :
    				sw[0] = 0
    				sw[1] = i1
    				tm    = x.arrive_time
    						# サービス終了時刻
    		for i1 in range(0, len(self.ent)) :
    			x = self.ent[i1]
    			if x.service > 0 and x.end_time <= tm :
    				sw[0] = 1
    				sw[1] = i1
    				tm    = x.end_time
    	
    		if sw[0] < 0 :
    			self.end = self.p_time
    	
    	##################################
    	# 終了処理
    	#      return : =-1 : 終了前処理
    	#               =-2 : 実際の終了
    	##################################
    
    	def End_o_s(self) :
    	
    		sw          = -2
    		self.p_time = self.end   # 現在時刻
    	
    		for i1 in range(0, len(self.ent)) :
    			x = self.ent[i1]
    			if x.service > 0 :   # サービス中の客はいるか?
    				if sw == -2 :
    					sw       = -1
    					self.end = x.end_time   # 窓口i1のサービス終了時刻
    				else :
    					if x.end_time > self.end :
    						self.end = x.end_time   # 窓口i1のサービス終了時刻
    	
    		return sw
    	
    	########################
    	# 客の到着処理
    	#      kk : 入り口番号
    	########################
    
    	def Arrive(self, kk) :
    				# 客数の増加と次の客の到着時刻の設定
    		self.nc      += 1   # 到着客数カウンタ
    		self.p_time   = self.inl[kk].arrive_time   # 現在時刻
    		if self.inl[kk].a_t == 0 :   # 次の客の到着時刻
    			self.inl[kk].arrive_time = self.p_time + expovariate(1.0 / self.inl[kk].mean)   
    		elif self.inl[kk].a_t == 1 :
    			self.inl[kk].arrive_time = self.p_time + self.inl[kk].mean   
    		else :
    			if len(self.inl[kk].que) < 1 :
    				self.inl[kk].arrive_time = -1.0
    			else :
    				self.inl[kk].arrive_time = self.inl[kk].que.pop(0)
    		if self.inl[kk].arrive_time >= self.end :
    			self.inl[kk].arrive_time = -1.0
    				# 系内客数の処理
    		self.c_now_c += len(self.cus) * (self.p_time - self.now_c_t)   # 系内客数にその数が継続した時間を乗じた値の累計
    		self.now_c_t  = self.p_time   # 現在の系内客数になった時刻
    		if len(self.cus)+1 > self.max_c :
    			self.max_c = len(self.cus) + 1   # 最大系内客数
    				# 空いている窓口を探す
    		k1 = self.inl[kk].out_n
    		self.que[k1].nc += 1
    		k = -1
    		for i1 in range(0, self.que[k1].m) :
    			k2 = self.que[k1].out_n[i1]   # 処理窓口
    			if self.ent[k2].service == 0 :
    				k = k2
    				break
    				# 窓口に空きがない場合
    		if k < 0 :
    			ct_p = Customer(0, k1, self.p_time)
    			self.cus[self.nc]  = ct_p   # 客の登録(系内客数)
    			self.que[k1].c_ql += len(self.que[k1].que) * (self.p_time - self.que[k1].ql_t)   # 待ち行列長にその長さが継続した時間を乗じた値の累計
    			self.que[k1].que.append(self.nc)   # 客の登録(待ち行列)
    			self.que[k1].ql_t = self.p_time   # 現在の待ち行列長になった時刻
    			if len(self.que[k1].que) > self.que[k1].max_q_l :
    				self.que[k1].max_q_l = len(self.que[k1].que)   # 最大待ち行列長
    				# すぐサービスをうけられる場合
    		else :
    			ct_p = Customer(1, k, self.p_time)
    			self.cus[self.nc]   = ct_p   # 客の登録(系内客数)
    			self.ent[k].service = self.nc   # サービスを受けている客番号
    			self.ent[k].busy_t  = self.p_time   # 窓口がふさがった時刻
    			if self.ent[k].s_t == 0 :   # 窓口のサービス終了時刻
    				self.ent[k].end_time = self.p_time + expovariate(1.0 / self.ent[k].mean)
    			else :
    				self.ent[k].end_time = self.p_time + self.ent[k].mean
    	
    	###################################
    	# サービス終了時の処理
    	#      kk : サービス終了窓口番号
    	###################################
    
    	def Service(self, kk) :
    				# 時間の設定
    		self.p_time = self.ent[kk].end_time   # 現在時刻
    		self.ent[kk].end_time = -1.0   # サービス終了時間
    				# システムの外へ出る場合
    		if self.ent[kk].to == 0 :
    				# 系内客数の処理
    			self.c_now_c += len(self.cus) * (self.p_time - self.now_c_t)   # 系内客数にその数が継続した時間を乗じた値の累計
    			self.now_c_t  = self.p_time   # 現在の系内客数になった時刻
    				# 滞在時間の処理
    			it = self.cus[self.ent[kk].service]   # サービス中の客
    			x1 = self.p_time - it.time
    			self.c_sys += x1   # 滞在時間の累計
    			if x1 > self.max_sys :
    				self.max_sys = x1   # 最大滞在時間
    			self.cus.pop(self.ent[kk].service)   # 客の削除(系内客数)
    				# 他の窓口処理へ入る場合の処理
    		else :
    			k1 = self.ent[kk].out_n
    			self.que[k1].nc += 1
    			sw = 1
    			k2 = 0
    			if len(self.que[k1].que) == 0 :
    				for i1 in range(0, self.que[k1].m) :
    					k2 = self.que[k1].out_n[i1]   # 窓口
    					if self.ent[k2].service == 0 :
    						sw = 0
    						break
    				# 待ち行列がある場合
    			if sw > 0 :
    				self.que[k1].c_ql += len(self.que[k1].que) * (self.p_time - self.que[k1].ql_t)   # 待ち行列長にその長さが継続した時間を乗じた値の累計
    				self.que[k1].que.append(self.ent[kk].service)   # 客の登録(待ち行列)
    				self.que[k1].ql_t = self.p_time   # 現在の待ち行列長になった時刻
    				if len(self.que[k1].que) > self.que[k1].max_q_l :
    					self.que[k1].max_q_l = len(self.que[k1].que)   # 最大待ち行列長
    				it = self.cus[self.ent[kk].service]
    				it.state1 = 0   # 客の状態変更(待ち行列)
    				it.state2 = self.ent[kk].out_n   # 客の状態変更(待ち行列番号)
    				# すぐサービスをうけられる場合
    			else :
    				self.ent[k2].service = self.ent[kk].service   # サービスを受けている客番号
    				self.ent[k2].busy_t  = self.p_time   # 窓口がふさがった時刻
    				if self.ent[k2].s_t == 0 :   # 窓口のサービス終了時刻
    					self.ent[k2].end_time = self.p_time + expovariate(1.0 / self.ent[k2].mean)
    				else :
    					self.ent[k2].end_time = self.p_time + self.ent[k2].mean
    				# 窓口使用時間の処理
    		self.ent[kk].service  = 0   # 窓口を空き状態にする
    		self.ent[kk].c_busy  += (self.p_time - self.ent[kk].busy_t)   # 窓口がふさがっている時間の累計
    				# この窓口に対する待ち行列がある場合
    		k3 = self.ent[kk].in_n
    		if len(self.que[k3].que) > 0 :
    			self.que[k3].c_ql += len(self.que[k3].que) * (self.p_time - self.que[k3].ql_t)   # 待ち行列長にその長さが継続した時間を乗じた値の累計
    			n = self.que[k3].que.pop(0)   # 待ち行列の先頭にいる客
    			self.que[k3].ql_t = self.p_time   # 現在の待ち行列長になった時刻
    			x1 = self.p_time - self.cus[n].time
    			self.que[k3].c_wt += x1   # 待ち時間の累計
    			if x1 > self.que[k3].max_wt :
    				self.que[k3].max_wt = x1   # 最大待ち時間
    			for i1 in range(0, self.que[k3].m) :
    				k4 = self.que[k3].out_n[i1]   # 窓口
    				if self.ent[k4].service == 0 :
    					self.ent[k4].service = n   # 窓口の客番号
    					self.ent[k4].busy_t  = self.p_time   # 窓口がふさがった時刻
    					if self.ent[k4].s_t == 0 :   # 窓口のサービス終了時刻
    						self.ent[k4].end_time = self.p_time + expovariate(1.0 / self.ent[k4].mean)
    					else :
    						self.ent[k4].end_time = self.p_time + self.ent[k4].mean
    					self.cus[n].state1 = 1   # 客の状態変更(サービス中)
    					self.cus[n].state2 = k4   # 客の状態変更(窓口番号)
    					break
    	
    	##########################
    	# 統計量の計算と最終出力
    	##########################
    
    	def Output(self) :
    						# System
    		print("全客数 {0:d}".format(self.nc), end="")
    		print(" 最大系内客数 {0:d} 最大滞在時間 {1:.3f}".format(self.max_c, self.max_sys))
    		print("平均系内客数 {0:.3f}".format(self.c_now_c / self.p_time), end="")
    		print(" 平均滞在時間 {0:.3f}".format(self.c_sys / self.nc), end="")
    		print(" 終了時間 {0:.3f}".format(self.p_time))
    						# Entity
    		for i1 in range(0, len(self.ent)) :
    			e = self.ent[i1]
    			print("Entity " + e.name, end="")
    			print(" 稼働率 {0:.3f}".format(e.c_busy / self.p_time))
    						# Queue
    		for i1 in range(0, len(self.que)) :
    			q = self.que[i1]
    			print("Queue " + q.name, end="")
    			print(" 客数 {0:d}".format(q.nc), end="")
    			print("   最大待ち行列長 {0:d}".format(q.max_q_l), end="")
    			print("   最大待ち時間 {0:.3f}".format(q.max_wt))
    			print("      平均待ち行列長 {0:.3f}".format(q.c_ql / self.p_time), end="")
    			print("   平均待ち時間 {0:.3f}".format(q.c_wt / q.nc))
    
    #############################
    # 複雑な待ち行列問題
    #      coded by Y.Suganuma
    #############################
    					# 入り口
    n_i = int(input("入り口(Inlet)の数は? "))
    inl = []
    for i1 in range(0, n_i) :
    	print(str(i1+1) + " 番目の入り口(Inlet)")
    	name1 = input("     名前は? ").strip(" \n")
    	qq    = []
    	n     = int(input("     到着分布(=0:指数分布,=1:一定時間間隔,<0:指定,客数の負値)? "))
    	if n == 0 :
    		m_a = float(input("          到着時間間隔の平均値は? "))
    	elif n == 1 :
    		m_a = float(input("          到着時間間隔は? "))
    	else :
    		for i2 in range(0, -n) :
    			x = float(input("          到着時間は? "))
    			qq.append(x)
    	name2 = input("     並ぶ待ち行列の名前は? ").strip(" \n")
    	inl_e = Inlet(name1, n, m_a, qq, name2)
    	inl.append(inl_e)
    				# 待ち行列
    n_q = int(input("待ち行列(Queue)の数は? "))
    que = []
    for i1 in range(0, n_q) :
    	print(str(i1+1) + " 番目の待ち行列(Queue)")
    	name1 = input("     名前は? ").strip(" \n")
    	n     = int(input("     入り口(0),または,窓口(n>0,窓口の数)から? "))
    	inn   = []
    	if n == 0 :
    		name2 = input("          入り口の名前は? ").strip(" \n")
    		inn.append(name2)
    	else :
    		for i2 in range(0, n) :
    			name3 = input("          " + str(i2+1) + " 番目の窓口の名前は? ").strip(" \n")
    			inn.append(name3)
    	m   = int(input("     処理する窓口の数は? "))
    	out = []
    	for i2 in range(0, m) :
    		name4 = input("          " +str(i2+1) + " 番目の窓口の名前は? ").strip(" \n")
    		out.append(name4)
    	que_e = Queue(name1, n, inn, m, out)
    	que.append(que_e)
    				# 窓口
    n_e = int(input("窓口(Entity)の数は? "))
    ent = []
    for i1 in range(0, n_e) :
    	print(str(i1+1) + " 番目の窓口(Entity)")
    	name1 = input("     名前は? ").strip(" \n")
    	s_t   = int(input("     サービス分布(=0:指数分布,=1:一定時間)? "))
    	if s_t == 0 :
    		m_s = float(input("          サービス時間の平均値は? "))
    	else :
    		m_s = float(input("          サービス時間は? "))
    	name2 = input("     待ち行列(入力)の名前は? ").strip(" \n")
    	sw    = int(input("     終了後,外部(0),または,待ち行列(1)? "))
    	name3 = ""
    	if sw > 0 :
    		name3 = input("          待ち行列(出力)の名前は? ").strip(" \n")
    	ent_e = Entity(name1, s_t, m_s, name2, sw, name3)
    	ent.append(ent_e)
    				# 全体の制御を行うクラス
    end  = float(input("シミュレーション終了時間? "))
    base = Q_base(inl, que, ent, end)   # 全体の制御を行うクラス
    				# 実行
    base.Control()
    				# 出力
    base.Output()
    
    """
    ------------入力例(簡単な場合)-----------
    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
    """
    			

  7. C#

    /******************************/
    /* 複雑な待ち行列問題         */
    /*      coded by Y.Suganuma   */
    /******************************/
    using System;
    using System.Collections.Generic;
    
    class Program
    {
    	/****************/
    	/* main program */
    	/****************/
    	static void Main()
    	{
    					// 入り口
    		Console.Write("入り口(Inlet)の数は? ");
    		int n_i = int.Parse(Console.ReadLine());
    		List <Inlet> inl = new List <Inlet>();
    		for (int i1 = 0; i1 < n_i; i1++) {
    			double m_a = 0.0;
    			Console.WriteLine((i1+1) + " 番目の入り口(Inlet)");
    			Console.Write("     名前は? ");
    			String name1 = Console.ReadLine().Trim();
    			Queue <double> que_i = new Queue <double>();
    			Console.Write("     到着分布(=0:指数分布,1=一定時間間隔,<0:指定:客数の負値))? ");
    			int n = int.Parse(Console.ReadLine());
    			if (n == 0) {
    				Console.Write("          到着時間間隔の平均値は? ");
    				m_a = double.Parse(Console.ReadLine());
    			}
    			else if (n == 1) {
    				Console.Write("          到着時間間隔は? ");
    				m_a = double.Parse(Console.ReadLine());
    			}
    			else {
    				double x;
    				for (int i2 = 0; i2 < -n; i2++) {
    					Console.Write("          到着時間は? ");
    					x = double.Parse(Console.ReadLine());
    					que_i.Enqueue(x);
    				}
    			}
    			Console.Write("     並ぶ待ち行列の名前は? ");
    			String name2 = Console.ReadLine().Trim();
    			Inlet inl_e  = new Inlet(name1, n, m_a, que_i, name2);
    			inl.Add(inl_e);
    		}
    						// 待ち行列
    		Console.Write("待ち行列(Queue)の数は? ");
    		int n_q = int.Parse(Console.ReadLine());
    		List <Wait_c> wt = new List <Wait_c>();
    		for (int i1 = 0; i1 < n_q; i1++) {
    			Console.WriteLine((i1+1) + " 番目の待ち行列(Queue)");
    			Console.Write("     名前は? ");
    			String name1 = Console.ReadLine().Trim();
    			Console.Write("     入り口(0),または,窓口(n>0,窓口の数)から? ");
    			int n = int.Parse(Console.ReadLine());
    			List <String> in1 = new List <String>();
    			if (n == 0) {
    				Console.Write("          入り口の名前は? ");
    				String name2 = Console.ReadLine().Trim();
    				in1.Add(name2);
    			}
    			else {
    				for (int i2 = 0; i2 < n; i2++) {
    					Console.Write("          " + (i2+1) + " 番目の窓口の名前は? ");
    					String name3 = Console.ReadLine().Trim();
    					in1.Add(name3);
    				}
    			}
    			Console.Write("     処理する窓口の数は? ");
    			int m = int.Parse(Console.ReadLine());
    			List <String> out1 = new List <String>();
    			for (int i2 = 0; i2 < m; i2++) {
    				Console.Write("          " + (i2+1) + " 番目の窓口の名前は? ");
    				String name4 = Console.ReadLine().Trim();
    				out1.Add(name4);
    			}
    			Wait_c wt_e = new Wait_c(name1, n, in1, m, out1);
    			wt.Add(wt_e);
    		}
    						// 窓口
    		Console.Write("窓口(Entity)の数は? ");
    		int n_e = int.Parse(Console.ReadLine());
    		List <Entity> ent = new List <Entity>();
    		for (int i1 = 0; i1 < n_e; i1++) {
    			double m_s = 0.0;
    			Console.WriteLine((i1+1) + " 番目の窓口(Entity)");
    			Console.Write("     名前は? ");
    			String name1 = Console.ReadLine().Trim();
    			Console.Write("     サービス分布(=0:指数分布,1=一定時間)? ");
    			int s_t = int.Parse(Console.ReadLine());
    			if (s_t == 0) {
    				Console.Write("          サービス時間の平均値は? ");
    				m_s = double.Parse(Console.ReadLine());
    			}
    			else {
    				Console.Write("          サービス時間は? ");
    				m_s = double.Parse(Console.ReadLine());
    			}
    			Console.Write("     待ち行列(入力)の名前は? ");
    			String name2 = Console.ReadLine().Trim();
    			Console.Write("     終了後,外部(0),または,待ち行列(1)? ");
    			int sw = int.Parse(Console.ReadLine());
    			String name3 = "";
    			if (sw > 0) {
    				Console.Write("          待ち行列(出力)の名前は? ");
    				name3 = Console.ReadLine().Trim();
    			}
    			Entity ent_e = new Entity(name1, s_t, m_s, name2, sw, name3);
    			ent.Add(ent_e);
    		}
    						// 全体の制御を行うクラス
    		Console.Write("シミュレーション終了時間? ");
    		double end = double.Parse(Console.ReadLine());
        	
    		Q_base base1 = new Q_base(inl, wt, ent, end);   // 全体の制御を行うクラス
    						// 実行
    		base1.Control();
    						// 出力
    		base1.Output();
    	}
    }
    
    /*********************/
    /* クラスInletの定義 */
    /*********************/
    class Inlet {
    	public String name;   // 入り口名
    	public String out1;   // 待ち行列名
    	public int out_n;   // 待ち行列番号
    	public double arrive_time;   // 客の到着時刻(負:客がない)
    	public int a_t;   // = -n : 到着する客の人数を負の値にしたもの
    	                  // =0 : 指数分布
    	                  // =1 : 一定時間間隔
    	public double mean;   // 到着時間間隔またはその平均
    	public Queue <double> que_i;   // 客の到着時刻リスト
    
    	/*************************************************************/
    	/* コンストラクタ                                            */
    	/*      name1 : 入り口名                                     */
    	/*      a_t1;   // = -n : 到着する客の人数を負の値にしたもの */
    	/*              // =0 : 指数分布                             */
    	/*              // =1 : 一定時間間隔                         */
    	/*      m_a: 到着時間間隔またはその平均                     */
    	/*      que1 : 客の到着時刻リスト                            */
    	/*      name2 : 待ち行列名                                   */
    	/*************************************************************/
    	public Inlet (String name1, int a_t1, double m_a, Queue<double> que1, String name2)
    	{
    		name  = name1;
    		out1  = name2;
    		mean  = m_a;
    		a_t   = a_t1;
    		que_i = que1;
    		if (a_t == 1)
    			arrive_time = 0;
    		else if (a_t < 0)
    			arrive_time = que_i.Dequeue();
    	}
    }
    
    /**********************/
    /* クラスWait_cの定義 */
    /**********************/
    class Wait_c {
    	public String name;   // 待ち行列名
    	public int nc;   // 待ち行列への到着客数カウンタ
    	public int max_q_l;   // 最大待ち行列長
    	public double c_ql;   // 待ち行列長にその長さが継続した時間を乗じた値の累計
    	public double ql_t;   // 現在の待ち行列長になった時間
    	public double max_wt;   // 最大待ち時間
    	public double c_wt;   // 待ち時間の累計
    	public int n;   // =0 : 入り口から入る
    	                // >0 : 複数の窓口から入る(窓口数)
    	public List <String> in1;   // 入り口名,または,窓口名
    	public List <int> in_n;   // 入り口番号,または,窓口番号
    	public int m;   // 処理する窓口数
    	public List <String> out1;   // 窓口名
    	public List <int> out_n;   // 窓口番号
    	public Queue <int> que;   // 待ち行列
    
    	/*********************************************/
    	/* コンストラクタ                            */
    	/*      name1 : 待ち行列名                   */
    	/*      n1 : =0 : 入り口から入る             */
    	/*           >0 : 複数の窓口から入る(窓口数) */
    	/*      in0 : 入り口名,または,窓口名       */
    	/*      m1 : 処理する窓口数                  */
    	/*      out0 : 窓口名                        */
    	/*********************************************/
    	public Wait_c(String name1, int n1, List<String> in0, int m1, List<String> out0)
    	{
    		name    = name1;
    		in1     = in0;
    		n       = n1;
    		in_n    = new List <int>();
    		out1    = out0;
    		m       = m1;
    		out_n   = new List <int>();
     		que     = new Queue <int>();
    		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 {
    	public String name;   // Entity名
    	public double busy_t;   // 窓口がふさがった時間
    	public double c_busy;   // 窓口がふさがっている時間の累計
    	public double end_time;   // サービス終了時間(負:何も処理していない)
    	public int s_t;   // =0 : 指数分布
    	                  // =1 : 一定時間
    	public double mean;   // 平均サービス時間
    	public int service;   // サービス中の客番号(0のときはなし)
    	public String in1;   // 待ち行列(入力)の名前
    	public int in_n;   // 待ち行列(入力)番号
    	public int to;   // =0 : システムの外に出る
    	                 // =1 : 待ち行列に入る
    	public String out1;   // 待ち行列(出力)の名前
    	public int out_n;   // 待ち行列(出力)番号
    
    	/****************************************/
    	/* コンストラクタ                       */
    	/*      name1 : 窓口名                  */
    	/*      s_t1;   // =0 : 指数分布        */
    	/*              // =1 : 一定時間        */
    	/*      m_s:サービス時間またはその平均 */
    	/*      name2 : 待ち行列(入力)の名前    */
    	/*      sw : =0 : システムの外に出る    */
    	/*           =1 : 待ち行列に入る        */
    	/*      name3 : 待ち行列(出力)の名前    */
    	/****************************************/
    	public Entity(String name1, int s_t1, double m_s, String name2, int sw, String name3)
    	{
    		name = name1;
    		to   = sw;
    		in1  = name2;
    		if (to > 0)
    			out1 = 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
    {
    	public double time;   // 到着時刻
    	public int state1;   // 客の状態1
                             //   =0 : 待ち行列に入っている
                             //   =1 : サービスを受けている
    	public int state2;   // 客の状態2(待ち行列番号,または,窓口番号)
    
    	/*********************/
    	/* コンストラクタ    */
    	/*      s1,s2 : 状態 */
    	/*      t : 到着時刻 */
    	/*********************/
    	public Customer(int s1, int s2, double t)
    	{
    		time   = t;
    		state1 = s1;
    		state2 = s2;
    	}
    }
    
    /**********************/
    /* クラスQ_baseの定義 */
    /**********************/
    class Q_base {
    	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 Dictionary <int, Customer> cus;   // 系内にいる客のリスト
    	private List <Inlet> inl;   // Inletオブジェクトリスト
    	private List <Wait_c> wt;   // Wait_cオブジェクトリスト
    	private List <Entity> ent;   // Entityオブジェクトリスト
    
    	/***************************************/
    	/* コンストラクタ                      */
    	/*      v_i : Inletオブジェクトリスト  */
    	/*      v_q : Wait_cオブジェクトリスト */
    	/*      v_e : Entityオブジェクトリスト */
    	/*      e : シミュレーション終了時刻   */
    	/***************************************/
    	public Q_base(List<Inlet> v_i, List<Wait_c> v_q, List<Entity> v_e, double e)
    	{
    					// 接続関係のチェック
    		Console.WriteLine();
    							// Inlet
    		inl = v_i;
    		wt  = v_q;
    		ent = v_e;
    		for (int i1 = 0; i1 < inl.Count-1; i1++) {
    			for (int i2 = i1+1; i2 < inl.Count; i2++) {
    				if (inl[i1].name == inl[i2].name) {
    					Console.WriteLine("***error 同じ名前の入り口があります " + inl[i1].name);
    					Environment.Exit(1);
    				}
    			}
    		}
    
    		int k;
    		for (int i1 = 0; i1 < inl.Count; i1++) {
    			k = -1;
    			for (int i2 = 0; i2 < wt.Count; i2++) {
    				if (inl[i1].out1 == wt[i2].name) {
    					k = i2;
    					break;
    				}
    			}
    			if (k >= 0)
    				inl[i1].out_n = k;
    			else {
    				Console.WriteLine("***error 入り口から入る待ち行列名が不適当です " + inl[i1].out1);
    				Environment.Exit(1);
    			}
    		}
    							// Queue
    		for (int i1 = 0; i1 < wt.Count-1; i1++) {
    			for (int i2 = i1+1; i2 < wt.Count; i2++) {
    				if (wt[i1].name == wt[i2].name) {
    					Console.WriteLine("***error 同じ名前の待ち行列があります " + wt[i1].name);
    					Environment.Exit(1);
    				}
    			}
    		}
    
    		for (int i1 = 0; i1 < wt.Count; i1++) {
    			if (wt[i1].n == 0) {
    				k = -1;
    				for (int i2 = 0; i2 < inl.Count; i2++) {
    					if (wt[i1].in1[0] == inl[i2].name) {
    						k = i2;
    						break;
    					}
    				}
    				if (k >= 0)
    					wt[i1].in_n.Add(k);
    				else {
    					Console.WriteLine("***error 待ち行列に入る入り口名が不適当です " + wt[i1].in1[0]);
    					Environment.Exit(1);
    				}
    			}
    			else {
    				for (int i2 = 0; i2 < wt[i1].n; i2++) {
    					k = -1;
    					for (int i3 = 0; i3 < ent.Count; i3++) {
    						if (wt[i1].in1[i2] == ent[i3].name) {
    							k = i3;
    							break;
    						}
    					}
    					if (k >= 0)
    						wt[i1].in_n.Add(k);
    					else {
    						Console.WriteLine("***error 待ち行列に入る窓口名が不適当です " + wt[i1].in1[i2]);
    						Environment.Exit(1);
    					}
    				}
    			}
    			for (int i2 = 0; i2 < wt[i1].m; i2++) {
    				k = -1;
    				for (int i3 = 0; i3 < ent.Count; i3++) {
    					if (wt[i1].out1[i2] == ent[i3].name) {
    						k = i3;
    						break;
    					}
    				}
    				if (k >= 0)
    					wt[i1].out_n.Add(k);
    				else {
    					Console.WriteLine("***error 待ち行列を処理する窓口名が不適当です " + wt[i1].out1[i2]);
    					Environment.Exit(1);
    				}
    			}
    		}
    							// Entity
    		for (int i1 = 0; i1 < ent.Count-1; i1++) {
    			k = -1;
    			for (int i2 = i1+1; i2 < ent.Count; i2++) {
    				if (ent[i1].name == ent[i2].name) {
    					Console.WriteLine("***error 同じ名前の窓口があります " + ent[i1].name);
    					Environment.Exit(1);
    				}
    			}
    		}
    
    		for (int i1 = 0; i1 < ent.Count; i1++) {
    			k = -1;
    			for (int i2 = 0; i2 < wt.Count; i2++) {
    				if (ent[i1].in1 == wt[i2].name) {
    					k = i2;
    					break;
    				}
    			}
    			if (k >= 0)
    				ent[i1].in_n = k;
    			else {
    				Console.WriteLine("***error 窓口に入る待ち行列名が不適当です " + ent[i1].in1);
    				Environment.Exit(1);
    			}
    			if (ent[i1].to > 0) {
    				k = -1;
    				for (int i2 = 0; i2 < wt.Count; i2++) {
    					if (ent[i1].out1 == wt[i2].name) {
    						k = i2;
    						break;
    					}
    				}
    				if (k >= 0)
    					ent[i1].out_n = k;
    				else {
    					Console.WriteLine("***error 窓口の出口にある待ち行列名が不適当です " + ent[i1].out1);
    					Environment.Exit(1);
    				}
    			}
    		}
    					// 初期設定
    		cus     = new Dictionary <int, 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());
    	}
    
    	/**************/
    	/* 全体の制御 */
    	/**************/
    	public void Control()
    	{
    					// 到着時間の初期設定
    		for (int i1 = 0; i1 < inl.Count; i1++) {
    			if (inl[i1].a_t == 0)
    				inl[i1].arrive_time = Exp_b(inl[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.Count; i1++) {
    			Inlet x = inl[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.Count; i1++) {
    			Entity x = ent[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.Count; i1++) {
    			Entity x = ent[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[kk].arrive_time;   // 現在時刻
    		if (inl[kk].a_t == 0)   // 次の客の到着時刻
    			inl[kk].arrive_time = p_time + Exp_b(inl[kk].mean);
    		else if (inl[kk].a_t == 1)
    			inl[kk].arrive_time = p_time + inl[kk].mean;
    		else {
    			if (inl[kk].que_i.Count == 0)
    				inl[kk].arrive_time = -1.0;
    			else
    				inl[kk].arrive_time = inl[kk].que_i.Dequeue();
    		}
    		if (inl[kk].arrive_time >= end)
    			inl[kk].arrive_time = -1.0;
    				//
    				// 系内客数の処理
    				//
    		c_now_c += cus.Count * (p_time - now_c_t);   // 系内客数にその数が継続した時間を乗じた値の累計
    		now_c_t  = p_time;   // 現在の系内客数になった時刻
    		if ((int)cus.Count+1 > max_c)
    			max_c = cus.Count + 1;   // 最大系内客数
    				//
    				// 空いている窓口を探す
    				//
    		int k1 = inl[kk].out_n;
    		wt[k1].nc++;
    		int k = -1;
    		for (int i1 = 0; i1 < wt[k1].m; i1++) {
    			int k2 = wt[k1].out_n[i1];   // 処理窓口
    			if (ent[k2].service == 0) {
    				k = k2;
    				break;
    			}
    		}
    				//
    				// 窓口に空きがない場合
    				//
    		if (k < 0) {
    			Customer ct_p = new Customer(0, k1, p_time);
    			cus.Add(nc, ct_p);   // 客の登録(系内客数)
    			wt[k1].c_ql += wt[k1].que.Count * (p_time - wt[k1].ql_t);   // 待ち行列長にその長さが継続した時間を乗じた値の累計
    			wt[k1].que.Enqueue(nc);   // 客の登録(待ち行列)
    			wt[k1].ql_t = p_time;   // 現在の待ち行列長になった時刻
    			if (wt[k1].que.Count > wt[k1].max_q_l)
    				wt[k1].max_q_l = wt[k1].que.Count;   // 最大待ち行列長
    		}
    				//
    				// すぐサービスをうけられる場合
    				//
    		else {
    			Customer ct_p = new Customer(1, k, p_time);
    			cus.Add(nc, ct_p);   // 客の登録(系内客数)
    			ent[k].service = nc;   // サービスを受けている客番号
    			ent[k].busy_t  = p_time;   // 窓口がふさがった時刻
    			if (ent[k].s_t == 0)   // 窓口のサービス終了時刻
    				ent[k].end_time = p_time + Exp_b(ent[k].mean);
    			else
    				ent[k].end_time = p_time + ent[k].mean;
    		}
    	}
    
    	/**********************************/
    	/* サービス終了時の処理           */
    	/*      kk : サービス終了窓口番号 */
    	/**********************************/
    	void Service(int kk)
    	{
    				//
    				// 時間の設定
    				//
    		p_time = ent[kk].end_time;   // 現在時刻
    		ent[kk].end_time = -1.0;   // サービス終了時間
    				//
    				// システムの外へ出る場合
    				//
    		if (ent[kk].to == 0) {
    				//
    				// 系内客数の処理
    				//
    			c_now_c += cus.Count * (p_time - now_c_t);   // 系内客数にその数が継続した時間を乗じた値の累計
    			now_c_t  = p_time;   // 現在の系内客数になった時刻
    				//
    				// 滞在時間の処理
    				//
    			Customer it = cus[ent[kk].service];   // サービス中の客
    			double   x1 = p_time - it.time;
    			c_sys      += x1;   // 滞在時間の累計
    			if (x1 > max_sys)
    				max_sys = x1;   // 最大滞在時間
    			cus.Remove(ent[kk].service);   // 客の削除(系内客数)
    		}
    				//
    				// 他の窓口処理へ入る場合の処理
    				//
    		else {
    			int k1 = ent[kk].out_n;
    			wt[k1].nc++;
    			int sw = 1;
    			int k2 = 0;
    			if (wt[k1].que.Count == 0) {
    				for (int i1 = 0; i1 < wt[k1].m; i1++) {
    					k2 = wt[k1].out_n[i1];   // 窓口
    					if (ent[k2].service == 0) {
    						sw = 0;
    						break;
    					}
    				}
    			}
    				//
    				// 待ち行列がある場合
    				//
    			if (sw > 0) {
    				wt[k1].c_ql += wt[k1].que.Count * (p_time - wt[k1].ql_t);   // 待ち行列長にその長さが継続した時間を乗じた値の累計
    				wt[k1].que.Enqueue(ent[kk].service);   // 客の登録(待ち行列)
    				wt[k1].ql_t = p_time;   // 現在の待ち行列長になった時刻
    				if (wt[k1].que.Count > wt[k1].max_q_l)
    					wt[k1].max_q_l = wt[k1].que.Count;   // 最大待ち行列長
    				Customer it = cus[ent[kk].service];
    				it.state1   = 0;   // 客の状態変更(待ち行列)
    				it.state2   = ent[kk].out_n;   // 客の状態変更(待ち行列番号)
    			}
    				//
    				// すぐサービスをうけられる場合
    				//
    			else {
    				ent[k2].service = ent[kk].service;   // サービスを受けている客番号
    				ent[k2].busy_t  = p_time;   // 窓口がふさがった時刻
    				if (ent[k2].s_t == 0)   // 窓口のサービス終了時刻
    					ent[k2].end_time = p_time + Exp_b(ent[k2].mean);
    				else
    					ent[k2].end_time = p_time + ent[k2].mean;
    			}
    		}
    				//
    				// 窓口使用時間の処理
    				//
    		ent[kk].service  = 0;   // 窓口を空き状態にする
    		ent[kk].c_busy  += (p_time - ent[kk].busy_t);   // 窓口がふさがっている時間の累計
    				//
    				// この窓口に対する待ち行列がある場合
    				//
    		int k3 = ent[kk].in_n;
    		if (wt[k3].que.Count > 0) {
    			wt[k3].c_ql += wt[k3].que.Count * (p_time - wt[k3].ql_t);   // 待ち行列長にその長さが継続した時間を乗じた値の累計
    			int n        = wt[k3].que.Dequeue();   // 待ち行列の先頭にいる客の削除
    			wt[k3].ql_t  = p_time;   // 現在の待ち行列長になった時刻
    			Customer it  = cus[n];
    			double x1    = p_time - it.time;
    			wt[k3].c_wt += x1;   // 待ち時間の累計
    			if (x1 > wt[k3].max_wt)
    				wt[k3].max_wt = x1;   // 最大待ち時間
    			for (int i1 = 0; i1 < wt[k3].m; i1++) {
    				int k4 = wt[k3].out_n[i1];   // 窓口
    				if (ent[k4].service == 0) {
    					ent[k4].service = n;   // 窓口の客番号
    					ent[k4].busy_t  = p_time;   // 窓口がふさがった時刻
    					if (ent[k4].s_t == 0)   // 窓口のサービス終了時刻
    						ent[k4].end_time = p_time + Exp_b(ent[k4].mean);
    					else
    						ent[k4].end_time = p_time + ent[k4].mean;
    					it.state1 = 1;   // 客の状態変更(サービス中)
    					it.state2 = k4;   // 客の状態変更(窓口番号)
    					break;
    				}
    			}
    		}
    	}
    
    	/**************************/
    	/* 統計量の計算と最終出力 */
    	/**************************/
    	public void Output()
    	{
    					// System
    		Console.Write("全客数 " + nc);
    		Console.WriteLine(" 最大系内客数 " + max_c + " 最大滞在時間 " + max_sys);
    		Console.Write("   平均系内客数 " + (c_now_c / p_time));
    		Console.Write(" 平均滞在時間 " + (c_sys / nc));
    		Console.WriteLine(" 終了時間 " + p_time);
    					// Entity
    		for (int i1 = 0; i1 < ent.Count; i1++) {
    			Entity e = ent[i1];
    			Console.WriteLine("Entity " + e.name + " 稼働率 " + (e.c_busy / p_time));
    		}
    					// Queue
    		for (int i1 = 0; i1 < wt.Count; i1++) {
    			Wait_c q = wt[i1];
    			Console.Write("Queue " + q.name + " 客数 " + q.nc);
    			Console.Write("   最大待ち行列長 " + q.max_q_l);
    			Console.WriteLine("   最大待ち時間 " + q.max_wt);
    			Console.Write("      平均待ち行列長 " + (q.c_ql / p_time));
    			Console.WriteLine("   平均待ち時間 " + (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
    */
    			

  8. VB

    '****************************'
    ' 複雑な待ち行列問題         '
    '      coded by Y.Suganuma   '
    '****************************'
    Imports System.IO
    Imports System.Collections.Generic
    
    Module Test
    
    	Sub Main()
    					' 入り口
    		Console.Write("入り口(Inlet)の数は? ")
    		Dim n_i As Integer = Integer.Parse(Console.ReadLine().Trim())
    		Dim inl As New List(Of Inlet)
    		For i1 As Integer = 0 To n_i-1
    			Dim m_a As Double = 0.0
    			Console.WriteLine((i1+1) & " 番目の入り口(Inlet)")
    			Console.Write("     名前は? ")
    			Dim name1 As String = Console.ReadLine().Trim()
    			Dim que_i As New Queue(Of Double)
    			Console.Write("     到着分布(=0:指数分布,1=一定時間間隔,<0:指定:客数の負値))? ")
    			Dim n As Integer = Integer.Parse(Console.ReadLine().Trim())
    			If n = 0
    				Console.Write("          到着時間間隔の平均値は? ")
    				m_a = Double.Parse(Console.ReadLine().Trim())
    			Else If n = 1
    				Console.Write("          到着時間間隔は? ")
    				m_a = Double.Parse(Console.ReadLine().Trim())
    			Else
    				Dim x As Double
    				For i2 As Integer = 0 To -n-1
    					Console.Write("          到着時間は? ")
    					x = Double.Parse(Console.ReadLine().Trim())
    					que_i.Enqueue(x)
    				Next
    			End If
    			Console.Write("     並ぶ待ち行列の名前は? ")
    			Dim name2 As String = Console.ReadLine().Trim()
    			Dim inl_e As Inlet  = new Inlet(name1, n, m_a, que_i, name2)
    			inl.Add(inl_e)
    		Next
    					' 待ち行列
    		Console.Write("待ち行列(Queue)の数は? ")
    		Dim n_q As Integer = Integer.Parse(Console.ReadLine().Trim())
    		Dim wt As New List(Of Wait_c)
    		For i1 As Integer = 0 To n_q-1
    			Console.WriteLine((i1+1) & " 番目の待ち行列(Queue)")
    			Console.Write("     名前は? ")
    			Dim name1 As String = Console.ReadLine().Trim()
    			Console.Write("     入り口(0),または,窓口(n>0,窓口の数)から? ")
    			Dim n As Integer = Integer.Parse(Console.ReadLine().Trim())
    			Dim in1 As New List(Of String)
    			If n = 0
    				Console.Write("          入り口の名前は? ")
    				Dim name2 As String = Console.ReadLine().Trim()
    				in1.Add(name2)
    			Else
    				For i2 As Integer = 0 To n-1
    					Console.Write("          " & (i2+1) & " 番目の窓口の名前は? ")
    					Dim name3 As String = Console.ReadLine().Trim()
    					in1.Add(name3)
    				Next
    			End If
    			Console.Write("     処理する窓口の数は? ")
    			Dim m As Integer = Integer.Parse(Console.ReadLine().Trim())
    			Dim out1 As New List (Of String)
    			For i2 As Integer = 0 To m-1
    				Console.Write("          " & (i2+1) & " 番目の窓口の名前は? ")
    				Dim name4 As String = Console.ReadLine().Trim()
    				out1.Add(name4)
    			Next
    			Dim wt_e As Wait_c = new Wait_c(name1, n, in1, m, out1)
    			wt.Add(wt_e)
    		Next
    					' 窓口
    		Console.Write("窓口(Entity)の数は? ")
    		Dim n_e As Integer = Integer.Parse(Console.ReadLine().Trim())
    		Dim ent As New List (Of Entity)
    		For i1 As Integer = 0 To n_e-1
    			Dim m_s As Double = 0.0
    			Console.WriteLine((i1+1) & " 番目の窓口(Entity)")
    			Console.Write("     名前は? ")
    			Dim name1 As String = Console.ReadLine().Trim()
    			Console.Write("     サービス分布(=0:指数分布,1=一定時間)? ")
    			Dim s_t As Integer = Integer.Parse(Console.ReadLine().Trim())
    			If s_t = 0
    				Console.Write("          サービス時間の平均値は? ")
    				m_s = Double.Parse(Console.ReadLine().Trim())
    			Else
    				Console.Write("          サービス時間は? ")
    				m_s = Double.Parse(Console.ReadLine().Trim())
    			End IF
    			Console.Write("     待ち行列(入力)の名前は? ")
    			Dim name2 As String = Console.ReadLine().Trim()
    			Console.Write("     終了後,外部(0),または,待ち行列(1)? ")
    			Dim sw As Integer = Integer.Parse(Console.ReadLine().Trim())
    			Dim name3 As String = ""
    			If sw > 0
    				Console.Write("          待ち行列(出力)の名前は? ")
    				name3 = Console.ReadLine().Trim()
    			End If
    			Dim ent_e As Entity = new Entity(name1, s_t, m_s, name2, sw, name3)
    			ent.Add(ent_e)
    		Next
    					' 全体の制御を行うクラス
    		Console.Write("シミュレーション終了時間? ")
    		Dim end_s As Double = Double.Parse(Console.ReadLine().Trim())
        	
    		Dim base1 As Q_base = new Q_base(inl, wt, ent, end_s)   ' 全体の制御を行うクラス
    						' 実行
    		base1.Control()
    						' 出力
    		base1.Output()
    
    	End Sub
    
    	'*******************'
    	' クラスInletの定義 '
    	'*******************'
    	Class Inlet
    
    		Public name As String   ' 入り口名
    		Public out1 As String   ' 待ち行列名
    		Public out_n As Integer   ' 待ち行列番号
    		Public arrive_time As Double   ' 客の到着時刻(負:客がない)
    		Public a_t As Integer   ' = -n : 到着する客の人数を負の値にしたもの
    		                        ' =0 : 指数分布
    		                        ' =1 : 一定時間間隔
    		Public mean As Double   ' 到着時間間隔またはその平均
    		Public que_i As New Queue(Of Double)   ' 客の到着時刻リスト
    
    		'***********************************************************'
    		' コンストラクタ                                            '
    		'      name1 : 入り口名                                     '
    		'      a_t1   ' = -n : 到着する客の人数を負の値にしたもの '
    		'              ' =0 : 指数分布                             '
    		'              ' =1 : 一定時間間隔                         '
    		'      m_a: 到着時間間隔またはその平均                     '
    		'      que1 : 客の到着時刻リスト                            '
    		'      name2 : 待ち行列名                                   '
    		'***********************************************************'
    		Public Sub New (name1 As String, a_t1 As Integer, m_a As Double, que1 As Queue(Of Double), name2 As String)
    
    			name  = name1
    			out1  = name2
    			mean  = m_a
    			a_t   = a_t1
    			que_i = que1
    			If a_t = 1
    				arrive_time = 0
    			ElseIf a_t < 0
    				arrive_time = que_i.Dequeue()
    			End If
    
    		End Sub
    
    	End Class
    
    	'********************'
    	' クラスWait_cの定義 '
    	'********************'
    	Class Wait_c
    
    		Public name As String   ' 待ち行列名
    		Public nc As Integer   ' 待ち行列への到着客数カウンタ
    		Public max_q_l As Integer   ' 最大待ち行列長
    		Public c_ql As Double   ' 待ち行列長にその長さが継続した時間を乗じた値の累計
    		Public ql_t As Double   ' 現在の待ち行列長になった時間
    		Public max_wt As Double   ' 最大待ち時間
    		Public c_wt As Double   ' 待ち時間の累計
    		Public n As Integer   ' =0 : 入り口から入る
    	                          ' >0 : 複数の窓口から入る(窓口数)
    		Public in1 As New List(Of String)   ' 入り口名,または,窓口名
    		Public in_n As New List(Of Integer)   ' 入り口番号,または,窓口番号
    		Public m As Integer   ' 処理する窓口数
    		Public out1 As New List(Of String)   ' 窓口名
    		Public out_n As New List(Of Integer)   ' 窓口番号
    		Public que As New Queue(Of Integer)   ' 待ち行列
    
    		'*******************************************'
    		' コンストラクタ                            '
    		'      name1 : 待ち行列名                   '
    		'      n1 : =0 : 入り口から入る             '
    		'           >0 : 複数の窓口から入る(窓口数) '
    		'      in0 : 入り口名,または,窓口名       '
    		'      m1 : 処理する窓口数                  '
    		'      out0 : 窓口名                        '
    		'*******************************************'
    		Public Sub New(name1 As String, n1 As Integer, in0 As List(Of String), m1 As Integer, out0 As List(Of String))
    
    			name    = name1
    			in1     = in0
    			n       = n1
    			out1    = out0
    			m       = m1
    			nc      = 0
    			max_q_l = 0
    			c_ql    = 0.0
    			ql_t    = 0.0
    			max_wt  = 0.0
    			c_wt    = 0.0
    
    		End Sub
    
    	End Class
    
    	'********************'
    	' クラスEntityの定義 '
    	'********************'
    	Class Entity
    	
    		Public name As String   ' Entity名
    		Public busy_t As Double   ' 窓口がふさがった時間
    		Public c_busy As Double   ' 窓口がふさがっている時間の累計
    		Public end_time As Double   ' サービス終了時間(負:何も処理していない)
    		Public s_t As Integer   ' =0 : 指数分布
    		                        ' =1 : 一定時間
    		Public mean As Double   ' 平均サービス時間
    		Public service As Integer   ' サービス中の客番号(0のときはなし)
    		Public in1 As String   ' 待ち行列(入力)の名前
    		Public in_n As Integer   ' 待ち行列(入力)番号
    		Public to_w As Integer   ' =0 : システムの外に出る
    		                         ' =1 : 待ち行列に入る
    		Public out1 As String   ' 待ち行列(出力)の名前
    		Public out_n As Integer   ' 待ち行列(出力)番号
    	
    		'**************************************'
    		' コンストラクタ                       '
    		'      name1 : 窓口名                  '
    		'      s_t1   ' =0 : 指数分布        '
    		'              ' =1 : 一定時間        '
    		'      m_s:サービス時間またはその平均 '
    		'      name2 : 待ち行列(入力)の名前    '
    		'      sw : =0 : システムの外に出る    '
    		'           =1 : 待ち行列に入る        '
    		'      name3 : 待ち行列(出力)の名前    '
    		'**************************************'
    		Public Sub New(name1 As String, s_t1 As Integer, m_s As Double, name2 As String, sw As Integer, name3 As String)
    
    			name = name1
    			to_w = sw
    			in1  = name2
    			If to_w > 0
    				out1 = name3
    			End If
    			end_time = -1.0
    			s_t      = s_t1
    			mean     = m_s
    			service  = 0
    			busy_t   = -1.0
    			c_busy   = 0.0
    	
    		End Sub
    	
    	End Class
    
    	'**********************'
    	' クラスCustomerの定義 '
    	'**********************'
    	Class Customer
    	
    		Public time As Double   ' 到着時刻
    		Public state1 As Integer   ' 客の状態1
    	                               '   =0 : 待ち行列に入っている
    	                               '   =1 : サービスを受けている
    		Public state2 As Integer   ' 客の状態2(待ち行列番号,または,窓口番号)
    	
    		'*******************'
    		' コンストラクタ    '
    		'      s1,s2 : 状態 '
    		'      t : 到着時刻 '
    		'*******************'
    		Public Sub New(s1 As Integer, s2 As Integer, t As Double)
    
    			time   = t
    			state1 = s1
    			state2 = s2
    
    		End Sub
    	
    	End Class
    
    	'********************'
    	' クラスQ_baseの定義 '
    	'********************'
    	Class Q_base
    	
    		Private p_time As Double   ' 現在時刻
    		Private max_c As Integer   ' 最大系内客数
    		Private nc As Integer   ' 到着客数カウンタ
    		Private now_c_t As Double   ' 現在の系内客数になった時間
    		Private c_now_c As Double   ' 系内客数にその数が継続した時間を乗じた値の累計
    		Private c_sys As Double   ' 滞在時間の累計
    		Private max_sys As Double   ' 最大滞在時間
    		Private end_s As Double   ' シミュレーション終了時間
    		Private rn As New Random()   ' 乱数
    		Private cus As New Dictionary(Of Integer, Customer)   ' 系内にいる客のリスト
    		Private inl As List(Of Inlet)   ' Inletオブジェクトリスト
    		Private wt As List(Of Wait_c)   ' Wait_cオブジェクトリスト
    		Private ent As List(Of Entity)   ' Entityオブジェクトリスト
    	
    		'*************************************'
    		' コンストラクタ                      '
    		'      v_i : Inletオブジェクトリスト  '
    		'      v_q : Wait_cオブジェクトリスト '
    		'      v_e : Entityオブジェクトリスト '
    		'      e : シミュレーション終了時刻   '
    		'*************************************'
    		Public Sub New(v_i As List(Of Inlet), v_q As List(Of Wait_c), v_e As List(Of Entity), e As Double)
    
    					' 接続関係のチェック
    			Console.WriteLine()
    							' Inlet
    			inl = v_i
    			wt  = v_q
    			ent = v_e
    			For i1 As Integer = 0 To inl.Count-2
    				For i2 As Integer = i1+1 To inl.Count-1
    					If inl(i1).name = inl(i2).name
    						Console.WriteLine("***error 同じ名前の入り口があります " & inl(i1).name)
    						Environment.Exit(1)
    					End If
    				Next
    			Next
    
    			Dim k As Integer
    			For i1 As Integer = 0 To inl.Count-1
    				k = -1
    				For i2 As Integer = 0 To wt.Count-1
    					If inl(i1).out1 = wt(i2).name
    						k = i2
    						Exit For
    					End If
    				Next
    				If k >= 0
    					inl(i1).out_n = k
    				Else
    					Console.WriteLine("***error 入り口から入る待ち行列名が不適当です " & inl(i1).out1)
    					Environment.Exit(1)
    				End If
    			Next
    							' Queue
    			For i1 As Integer = 0 To wt.Count-2
    				For i2 As Integer = i1+1 To wt.Count-1
    					If wt(i1).name = wt(i2).name
    						Console.WriteLine("***error 同じ名前の待ち行列があります " & wt(i1).name)
    						Environment.Exit(1)
    					End If
    				Next
    			Next
    
    			For i1 As Integer = 0 To wt.Count-1
    				If wt(i1).n = 0
    					k = -1
    					For i2 As Integer = 0 To inl.Count-1
    						If wt(i1).in1(0) = inl(i2).name
    							k = i2
    							Exit For
    						End If
    					Next
    					If k >= 0
    						wt(i1).in_n.Add(k)
    					Else
    						Console.WriteLine("***error 待ち行列に入る入り口名が不適当です " & wt(i1).in1(0))
    						Environment.Exit(1)
    					End If
    				Else
    					For i2 As Integer = 0 To wt(i1).n-1
    						k = -1
    						For i3 As Integer = 0 To ent.Count-1
    							If wt(i1).in1(i2) = ent(i3).name
    								k = i3
    								Exit For
    							End If
    						Next
    						If k >= 0
    							wt(i1).in_n.Add(k)
    						Else
    							Console.WriteLine("***error 待ち行列に入る窓口名が不適当です " & wt(i1).in1(i2))
    							Environment.Exit(1)
    						End If
    					Next
    				End If
    				For i2 As Integer = 0 To wt(i1).m-1
    					k = -1
    					For i3 As Integer = 0 To ent.Count-1
    						If wt(i1).out1(i2) = ent(i3).name
    							k = i3
    							Exit For
    						End If
    					Next
    					If k >= 0
    						wt(i1).out_n.Add(k)
    					Else
    						Console.WriteLine("***error 待ち行列を処理する窓口名が不適当です " & wt(i1).out1(i2))
    						Environment.Exit(1)
    					End If
    				Next
    			Next
    							' Entity
    			For i1 As Integer = 0 To ent.Count-2
    				k = -1
    				For i2 As Integer = i1+1 To ent.Count-1
    					If ent(i1).name = ent(i2).name
    						Console.WriteLine("***error 同じ名前の窓口があります " & ent(i1).name)
    						Environment.Exit(1)
    					End If
    				Next
    			Next
    
    			For i1 As Integer = 0 To ent.Count-1
    				k = -1
    				For i2 As Integer = 0 To wt.Count-1
    					If ent(i1).in1 = wt(i2).name
    						k = i2
    						Exit For
    					End If
    				Next
    				If k >= 0
    					ent(i1).in_n = k
    				Else
    					Console.WriteLine("***error 窓口に入る待ち行列名が不適当です " & ent(i1).in1)
    					Environment.Exit(1)
    				End If
    				If ent(i1).to_w > 0
    					k = -1
    					For i2 As Integer = 0 To wt.Count-1
    						If ent(i1).out1 = wt(i2).name
    							k = i2
    							Exit For
    						End If
    					Next
    					If k >= 0
    						ent(i1).out_n = k
    					Else
    						Console.WriteLine("***error 窓口の出口にある待ち行列名が不適当です " & ent(i1).out1)
    						Environment.Exit(1)
    					End If
    				End If
    			Next
    					' 初期設定
    			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_s   = e
    
    		End Sub
    
    		'********************'
    		' 指数分布乱数の発生 '
    		'      m : 平均値    '
    		'      rerutn : 乱数 '
    		'********************'
    		Function Exp_b(m As Double)
    			Return -m * Math.Log(rn.NextDouble())
    		End Function
    
    		'************'
    		' 全体の制御 '
    		'************'
    		Public Sub Control()
    
    					' 到着時間の初期設定
    			For i1 As Integer = 0 To inl.Count-1
    				If inl(i1).a_t = 0
    					inl(i1).arrive_time = Exp_b(inl(i1).mean)
    				End If
    			Next
    					' 実行制御
    			Dim sw(2) As Integer
    			sw(0) = 0
    			Do While sw(0) > -2
    				Next_e(sw)   ' 次の処理の選択
    				If sw(0) = -1
    					sw(0) = End_o_s()   ' シミュレーションの終了
    				Else
    					If sw(0) = 0
    						Arrive(sw(1))   ' 客の到着処理
    					Else
    						Service(sw(1))   ' サービスの終了
    					End If
    				End If
    			Loop
    
    		End Sub
    
    		'*******************************************'
    		' 次の処理の決定                            '
    		'      sw(0) : =-1 : シミュレーションの終了 '
    		'              =0  : 客の到着処理           '
    		'              =1  : 窓口のサービス終了     '
    		'        (1) : 入り口番号 or 窓口番号       '
    		'*******************************************'
    		Sub Next_e(sw() As Integer)
    
    			Dim tm As Double = end_s   ' 次の処理時刻
    			sw(0)            = -1
    						' 次の客の到着時刻
    			For i1 As Integer = 0 To inl.Count-1
    				Dim x As Inlet = inl(i1)
    				If x.arrive_time >= 0.0 and x.arrive_time < tm
    					sw(0) = 0
    					sw(1) = i1
    					tm    = x.arrive_time
    				End If
    			Next
    						' サービス終了時刻
    			For i1 As Integer = 0 To ent.Count-1
    				Dim x As Entity = ent(i1)
    				If x.service > 0 and x.end_time <= tm
    					sw(0) = 1
    					sw(1) = i1
    					tm    = x.end_time
    				 End If
    			Next
    
    			If sw(0) < 0
    				end_s = p_time
    			End If
    
    		End Sub
    
    		'********************************'
    		' 終了処理                       '
    		'      return : =-1 : 終了前処理 '
    		'               =-2 : 実際の終了 '
    		'********************************'
    		Function End_o_s()
    
    			Dim sw As Integer = -2
    			p_time            = end_s   ' 現在時刻
    
    			For i1 As Integer = 0 To ent.Count-1
    				Dim x As Entity = ent(i1)
    				If x.service > 0   ' サービス中の客はいるか?
    					If sw = -2
    						sw  = -1
    						end_s = x.end_time   ' 窓口i1のサービス終了時刻
    					Else
    						If x.end_time > end_s
    							end_s = x.end_time   ' 窓口i1のサービス終了時刻
    						End If
    					End If
    				End If
    			Next
    	
    			Return sw
    	
    		End Function
    	
    		'**********************'
    		' 客の到着処理         '
    		'      kk : 入り口番号 '
    		'**********************'
    		Sub Arrive(kk As Integer)
    				'
    				' 客数の増加と次の客の到着時刻の設定
    				'
    			nc     += 1   ' 到着客数カウンタ
    			p_time  = inl(kk).arrive_time   ' 現在時刻
    			If inl(kk).a_t = 0   ' 次の客の到着時刻
    				inl(kk).arrive_time = p_time + Exp_b(inl(kk).mean)
    			ElseIf inl(kk).a_t = 1
    				inl(kk).arrive_time = p_time + inl(kk).mean
    			Else
    				If inl(kk).que_i.Count = 0
    					inl(kk).arrive_time = -1.0
    				Else
    					inl(kk).arrive_time = inl(kk).que_i.Dequeue()
    				End If
    			End If
    			If inl(kk).arrive_time >= end_s
    				inl(kk).arrive_time = -1.0
    			End If
    				'
    				' 系内客数の処理
    				'
    			c_now_c += cus.Count * (p_time - now_c_t)   ' 系内客数にその数が継続した時間を乗じた値の累計
    			now_c_t  = p_time   ' 現在の系内客数になった時刻
    			If cus.Count+1 > max_c
    				max_c = cus.Count + 1   ' 最大系内客数
    			End If
    				'
    				' 空いている窓口を探す
    				'
    			Dim k1 As Integer = inl(kk).out_n
    			wt(k1).nc        += 1
    			Dim k As Integer  = -1
    			For i1 As Integer = 0 To wt(k1).m-1
    				Dim k2 As Integer = wt(k1).out_n(i1)   ' 処理窓口
    				If ent(k2).service = 0
    					k = k2
    					Exit For
    				End If
    			Next
    				'
    				' 窓口に空きがない場合
    				'
    			If k < 0
    				Dim ct_p As Customer = new Customer(0, k1, p_time)
    				cus.Add(nc, ct_p)   ' 客の登録(系内客数)
    				wt(k1).c_ql += wt(k1).que.Count * (p_time - wt(k1).ql_t)   ' 待ち行列長にその長さが継続した時間を乗じた値の累計
    				wt(k1).que.Enqueue(nc)   ' 客の登録(待ち行列)
    				wt(k1).ql_t = p_time   ' 現在の待ち行列長になった時刻
    				If wt(k1).que.Count > wt(k1).max_q_l
    					wt(k1).max_q_l = wt(k1).que.Count   ' 最大待ち行列長
    				End If
    				'
    				' すぐサービスをうけられる場合
    				'
    			Else
    				Dim ct_p As Customer = new Customer(1, k, p_time)
    				cus.Add(nc, ct_p)   ' 客の登録(系内客数)
    				ent(k).service = nc   ' サービスを受けている客番号
    				ent(k).busy_t  = p_time   ' 窓口がふさがった時刻
    				If ent(k).s_t = 0   ' 窓口のサービス終了時刻
    					ent(k).end_time = p_time + Exp_b(ent(k).mean)
    				Else
    					ent(k).end_time = p_time + ent(k).mean
    				End If
    			End If
    
    		End Sub
    
    		'********************************'
    		' サービス終了時の処理           '
    		'      kk : サービス終了窓口番号 '
    		'********************************'
    		Sub Service(kk As Integer)
    				'
    				' 時間の設定
    				'
    			p_time           = ent(kk).end_time   ' 現在時刻
    			ent(kk).end_time = -1.0   ' サービス終了時間
    				'
    				' システムの外へ出る場合
    				'
    			If ent(kk).to_w = 0
    				'
    				' 系内客数の処理
    				'
    				c_now_c += cus.Count * (p_time - now_c_t)   ' 系内客数にその数が継続した時間を乗じた値の累計
    				now_c_t  = p_time   ' 現在の系内客数になった時刻
    				'
    				' 滞在時間の処理
    				'
    				Dim it As Customer = cus(ent(kk).service)   ' サービス中の客
    				Dim x1 As Double   = p_time - it.time
    				c_sys             += x1   ' 滞在時間の累計
    				If x1 > max_sys
    					max_sys = x1   ' 最大滞在時間
    				End If
    				cus.Remove(ent(kk).service)   ' 客の削除(系内客数)
    				'
    				' 他の窓口処理へ入る場合の処理
    				'
    			Else
    				Dim k1 As Integer = ent(kk).out_n
    				wt(k1).nc        += 1
    				Dim sw As Integer = 1
    				Dim k2 As Integer = 0
    				If wt(k1).que.Count = 0
    					For i1 As Integer = 0 To wt(k1).m-1
    						k2 = wt(k1).out_n(i1)   ' 窓口
    						If ent(k2).service = 0
    							sw = 0
    							Exit For
    						End If
    					Next
    				End If
    				'
    				' 待ち行列がある場合
    				'
    				If sw > 0
    					wt(k1).c_ql += wt(k1).que.Count * (p_time - wt(k1).ql_t)   ' 待ち行列長にその長さが継続した時間を乗じた値の累計
    					wt(k1).que.Enqueue(ent(kk).service)   ' 客の登録(待ち行列)
    					wt(k1).ql_t = p_time   ' 現在の待ち行列長になった時刻
    					If wt(k1).que.Count > wt(k1).max_q_l
    						wt(k1).max_q_l = wt(k1).que.Count   ' 最大待ち行列長
    					End If
    					Dim it As Customer = cus(ent(kk).service)
    					it.state1          = 0   ' 客の状態変更(待ち行列)
    					it.state2          = ent(kk).out_n   ' 客の状態変更(待ち行列番号)
    				'
    				' すぐサービスをうけられる場合
    				'
    				Else
    					ent(k2).service = ent(kk).service   ' サービスを受けている客番号
    					ent(k2).busy_t  = p_time   ' 窓口がふさがった時刻
    					If ent(k2).s_t = 0   ' 窓口のサービス終了時刻
    						ent(k2).end_time = p_time + Exp_b(ent(k2).mean)
    					Else
    						ent(k2).end_time = p_time + ent(k2).mean
    					End If
    				End If
    			End If
    				'
    				' 窓口使用時間の処理
    				'
    			ent(kk).service  = 0   ' 窓口を空き状態にする
    			ent(kk).c_busy  += (p_time - ent(kk).busy_t)   ' 窓口がふさがっている時間の累計
    				'
    				' この窓口に対する待ち行列がある場合
    				'
    			Dim k3 As Integer = ent(kk).in_n
    			If wt(k3).que.Count > 0
    				wt(k3).c_ql       += wt(k3).que.Count * (p_time - wt(k3).ql_t)   ' 待ち行列長にその長さが継続した時間を乗じた値の累計
    				Dim n As Integer   = wt(k3).que.Dequeue()   ' 待ち行列の先頭にいる客の削除
    				wt(k3).ql_t        = p_time   ' 現在の待ち行列長になった時刻
    				Dim it As Customer = cus(n)
    				Dim x1 As Double   = p_time - it.time
    				wt(k3).c_wt       += x1   ' 待ち時間の累計
    				If x1 > wt(k3).max_wt
    					wt(k3).max_wt = x1   ' 最大待ち時間
    				End If
    				For i1 As Integer = 0 To wt(k3).m-1
    					Dim k4 As Integer = wt(k3).out_n(i1)   ' 窓口
    					If ent(k4).service = 0
    						ent(k4).service = n   ' 窓口の客番号
    						ent(k4).busy_t  = p_time   ' 窓口がふさがった時刻
    						If ent(k4).s_t = 0   ' 窓口のサービス終了時刻
    							ent(k4).end_time = p_time + Exp_b(ent(k4).mean)
    						Else
    							ent(k4).end_time = p_time + ent(k4).mean
    						End If
    						it.state1 = 1   ' 客の状態変更(サービス中)
    						it.state2 = k4   ' 客の状態変更(窓口番号)
    						Exit For
    					End If
    				Next
    			End If
    
    		End Sub
    
    		'************************'
    		' 統計量の計算と最終出力 '
    		'************************'
    		Public Sub Output()
    					' System
    			Console.Write("全客数 " & nc)
    			Console.WriteLine(" 最大系内客数 " & max_c & " 最大滞在時間 " & max_sys)
    			Console.Write("   平均系内客数 " & (c_now_c / p_time))
    			Console.Write(" 平均滞在時間 " & (c_sys / nc))
    			Console.WriteLine(" 終了時間 " & p_time)
    					' Entity
    			For i1 As Integer = 0 To ent.Count-1
    				Dim e As Entity = ent(i1)
    				Console.WriteLine("Entity " & e.name & " 稼働率 " & (e.c_busy / p_time))
    			Next
    					' Queue
    			For i1 As Integer = 0 To wt.Count-1
    				Dim q As Wait_c = wt(i1)
    				Console.Write("Queue " & q.name & " 客数 " & q.nc)
    				Console.Write("   最大待ち行列長 " & q.max_q_l)
    				Console.WriteLine("   最大待ち時間 " & q.max_wt)
    				Console.Write("      平均待ち行列長 " & (q.c_ql / p_time))
    				Console.WriteLine("   平均待ち時間 " & (q.c_wt / q.nc))
    			Next
    
    		End Sub
    
    	End Class
    
    End Module
    
    /*
    ------------入力例(簡単な場合)-----------
    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
    */
    			

静岡理工科大学 菅沼ホーム 目次 索引