銀行排隊問題(詳解隊列)
這算是我入園的第一篇筆記咯~
【問題描述】
一個系統模仿另一個系統行為的技術稱為模擬,如飛行模擬器。模擬可以用來進行方案論證、人員培訓和改進服務。計算機技術常用於模擬系統中。
生產者-消費者(Server-Custom)是常見的應用模式,見於銀行、食堂、打印機、醫院、超等提供服務和使用服務的應用中。這類應用的主要問題是消費者如果等待(排隊)時間過長,會引發用戶抱怨,影響服務質量;如果提供服務者(服務窗口)過多,將提高運管商成本。(經濟學中排隊論)
假設某銀行網點有五個服務窗口,分別為三個對私、一個對公和一個外幣窗口。銀行服務的原則是先來先服務。通常對私業務人很多,其它窗口人則較少,可臨時改為對私服務。假設當對私窗口等待服務的客戶(按實際服務窗口)平均排隊人數超過(大於或等於)7人時,等待客戶將可能有抱怨,影響服務質量,此時銀行可臨時將其它窗口中一個或兩個改為對私服務,當客戶少於7人時,將立即恢復原有業務。設計一個程序用來模擬銀行服務。
說明:
1. 增加服務窗口將會增加成本或影響其它業務,因此,以成本增加或影響最小為原則來增加服務窗口,即如果增加一個窗口就能使得按窗口平均等待服務人數小於7人,則只增加一個窗口。一旦按窗口平均等待服務人數小於7人,就減少一個所增加的窗口。
2. 為了簡化問題,假設新到客戶是在每個服務周期開始時到達。
3. 當等待服務人數發生變化時(新客戶到達或有客戶已接受服務),則及時計算按實際服務窗口平均等待服務人數,並按相應策略調整服務窗口數(增加或減少額外的服務窗口,但對私窗口不能減少)。註意:只在獲取新客戶(不管到達新客戶數是否為0)時或已有客戶去接受服務時,才按策略調整服務窗口數。進一步講,增加服務窗口只在有客戶到達的周期內進行(也就是說增加窗口是基於客戶的感受,銀行對增加窗口是不情願的,因為要增加成本,一旦不再有新客戶來,銀行是不會再增加服務窗口的);一旦有客戶去接受服務(即等待客戶減少),銀行將根據策略及時減少服務窗口,因此,在每個周期內,有客戶去接受服務後要馬上判斷是否減少服務窗口(因為能減少成本,銀行是積極的)
本問題中假設對公和對外幣服務窗口在改為對私服務時及服務期間沒有相應因公或外幣服務新客戶到達(即正好空閑),同時要求以增加成本或影響最小為前提,來盡最大可能減少對私服務客戶等待時間。
【輸入形式】
首先輸入一個整數表示時間周期數,然後再依次輸入每個時間周期中因私業務的客戶數。註:一個時間周期指的是銀行處理一筆業務的平均處理時間,可以是一分鐘、三分鐘或其它。例如:
6
2 5 13 11 15 9
說明:表明在6個時間周期內,第1個周期來了2個(序號分別為1,2),第2個來了5人(序號分別為3,4,5,6,7),以此類推。
【輸出形式】
每個客戶等待服務的時間周期數。輸出形式如下:
用戶序號 : 等待周期數
說明:客戶序號與等待周期數之間用符號:分隔,冒號(:)兩邊各有一個空格,等待周期數後直接為回車。
【樣例輸入】
4
2 5 13 11
【樣例輸出】
1 : 0
2 : 0
3 : 0
4 : 0
5 : 0
6 : 1
7 : 1
8 : 0
9 : 1
10 : 1
11 : 1
12 : 1
13 : 2
14 : 2
15 : 2
16 : 3
17 : 3
18 : 3
19 : 4
20 : 4
21 : 3
22 : 4
23 : 4
24 : 4
25 : 5
26 : 5
27 : 5
28 : 6
29 : 6
30 : 6
31 : 7
【樣例說明】
樣例輸入表明有四個時間周期,第一個周期來了2人(序號1-2);第二個周期來了5人(序號3-7);第三個周期來了13人(序號8-20);第四個周期來了11人(序號21-31)。由於第一個時間周期內只來了2人,銀行(有三個服務窗口)能及時提供服務,因此客戶等待時間為0;第二個時間周期內來了5人,銀行一個周期內一次只能服務3人,另有2個在下個周期內服務,因此等待時間為1,其它類推。
【評分標準】
通過所有測試點得滿分。
1 #include<stdio.h> 2 #include<stdlib.h> 3 4 #define MAXSIZE 200//隊列裏面的總人數 5 #define MINSVR 3//當銀行正常的時候一個時間周期只能服務3個人 6 #define MAXSVR 5//銀行功能全開,最多一個周期服務5個人 7 #define NUMBER 7//正常服務時的人數最大限 8 9 /*說明: 10 在生產者-消費者應用中消費者顯然是先來先得到服務。在此,顯然 11 可用一個隊列來存放等待服務的客戶隊列。每個客戶有二個基本屬性: 12 排隊序號和等待時間(時間周期數) 13 14 等待服務的客戶隊列,一個循環隊列 15 16 偽代碼核心算法: 17 18 for(clock=1; ; clock++) //在每個時間周期內 19 { 20 1. If 客戶等待隊列非空 21 將每個客戶的等待時間增加一個時間單元; 22 2. If(clock <= simulationtime) 23 2.1 如果有新客戶到來(從輸入中讀入本周期內新來客戶數),將其入隊; 24 2.2 根據等待服務客戶數重新計算服務窗口數; 25 3. If 客戶等待隊列非空 26 3.1 從客戶隊列中取(出隊)相應數目(按實際服務窗口數)客戶獲得服務; 27 3.2 然後根據等待服務客戶數重新計算服務窗口數; 28 Else 結束模擬 29 } 30 */ 31 /* 32 理解: 33 對於排隊問題,可以劃分為處理元,將所有的數據全部入隊,排成線性結構 34 然後按照銀行的處理能力(處理元)依次出隊,此間每經歷一次周期就更新 35 一次數據,並且相應地對客戶的等待時間進行增加處理 36 */ 37 38 ///所以對於排隊現狀的更新是按照時間周期來的/// 39 //定義結構,對於每一個客戶,id代表其編號,wait_time表示其等待時間 40 typedef struct 41 { 42 int id; 43 int wait_time; 44 }Cust; 45 46 //設立隊列 47 Cust queue[MAXSIZE]; 48 49 int front = 0,real = -1,people_count = 0; 50 //people_count為隊列中的人數,是判斷隊列是否為空的指標 51 52 53 int normal_sev_time = MINSVR;//正常的工作時間 54 55 ///---------函數------------/// 56 //int isEmpty(); /// 57 //int isFull(); /// 58 //void enQueue(Cust q); /// 59 //Cust deQueue(); /// 60 //void updatetime(); /// 61 //void arriveCust(); /// 62 //void service(); /// 63 ///-------------------------/// 64 65 //判斷隊列是否為空 66 int isEmpty() 67 { 68 return people_count == 0; 69 } 70 71 72 //判斷隊列是否滿員 73 int isFull() 74 { 75 return people_count == MAXSIZE; 76 } 77 78 79 //將q元素進入隊列 80 void enQueue(Cust q) 81 { 82 83 if(isFull()) 84 exit(-1); 85 86 else 87 { 88 //數據周期覆蓋 89 real=(real+1)%MAXSIZE; 90 queue[real]=q; 91 //人數++ 92 people_count++; 93 } 94 return; 95 } 96 97 98 //出隊,同時取出隊首元素q 99 Cust deQueue() 100 { 101 Cust q; 102 //判斷隊列是否為空 103 if(isEmpty()) 104 exit(-1); 105 106 else 107 { 108 //開始時front == 0,代表隊首 109 q=queue[front]; 110 //隊首指針向後移動 111 front=(front+1)%MAXSIZE; 112 113 //人數-- 114 people_count--; 115 } 116 return q; 117 } 118 119 120 //對所有的客戶的等待時間進行更新 121 void updatetime() 122 { 123 int i; 124 for(i=0;i<people_count;i++) 125 queue[(front+i) % MAXSIZE].wait_time++; 126 //front表示從隊首開始,從頭開始每位客戶的候時加一 127 return; 128 } 129 130 131 132 //對於新到來的客戶的入隊或者開啟備用窗口操作 133 void arriveCust() 134 { 135 //靜態局部變量 136 static int count=1; 137 int i,n; 138 139 Cust q; 140 //讀入該個時間周期裏面的客戶數量 141 scanf("%d",&n); 142 143 //更改每個客戶的id號,並入隊 144 for(i=0;i<n;i++) 145 { 146 q.id = count++;//id號碼更改 147 q.wait_time=0;//客戶候時初始化 148 enQueue(q); 149 } 150 151 //核心 152 while((people_count/normal_sev_time) >= NUMBER && normal_sev_time < MAXSVR) 153 //根據需求開始加窗口,但是不可以超過5 154 normal_sev_time++; 155 156 return; 157 } 158 159 160 161 162 void service() 163 { 164 int i; 165 Cust q; 166 167 //每次出隊相應的人數(窗口數) 168 for(i=0;i < normal_sev_time;i++) 169 { 170 //如果隊列裏面為空就直接返回 171 if(isEmpty()) 172 return; 173 174 else 175 { 176 q=deQueue(); 177 printf("%d : %d\n",q.id,q.wait_time); 178 } 179 } 180 181 //出隊時實時更新關閉多余的窗口 182 while((people_count/normal_sev_time) < NUMBER && normal_sev_time > MINSVR) 183 normal_sev_time--; 184 185 return; 186 } 187 188 int main() 189 { 190 int clock,loop; 191 192 //周期數 193 scanf("%d",&loop); 194 195 clock=1; 196 while(1) 197 { 198 //如果隊列顯示不為空,實時更新候時 199 if(!isEmpty()) 200 updatetime(); 201 202 //讀入一次客戶 203 if(clock <= loop) 204 arriveCust(); 205 206 //處理 207 service(); 208 209 210 if(people_count == 0 && clock > loop) 211 break; 212 213 214 clock++; 215 } 216 return 0; 217 }
銀行排隊問題(詳解隊列)