1 package cn.edu.karel.work.public_transit_problem;
2
3 import java.io.File;
4 import java.io.FileNotFoundException;
5 import java.io.FileReader;
6 import java.io.IOException;
7 import java.util.ArrayList;
8 import java.util.List;
9
10 /**
11 * GreedSolute类
12 *
13 * @author Karel Zuo
14 * @time 2015.6.4
15 * @version 1.0
16 * @description 贪心算法求解公交时刻表和车次链问题
17 */
18 public class GreedSolute {
19 /** 发车时刻表数据 */
20 static File forward = new File("D:/mycode/Eclipse/Bus Scheduel Problem/scheduel1/ForwardScheduel/start time.txt");
21 static File backward = new File("D:/mycode/Eclipse/Bus Scheduel Problem/scheduel1/BackScheduel/start time.txt");
22 static int sum = 0;
23
24 public static void main(String[] args) throws IOException{
25 /** 创建时刻表 */
26 Scheduel scheduel = new Scheduel();
27 inputForward(scheduel);
28 inputBackward(scheduel);
29
30 /** 固定行车计划 */
31 ArrayList<TrainsitChain> chain = creatFixedPlan(scheduel);
32
33 /** 可变行车计划 */
34 //chain = creatVariablePlan(scheduel,chain);
35 }
36
37 /**
38 * 将发车时刻表中的所有车次按照 FIFO规则排序
39 *
40 * @param scheduel 发车时刻表
41 * @return list 排序后的车次序号列表
42 */
43 public static ArrayList<Integer> sortScheduel(Scheduel scheduel){
44 /** 排序后的车次序号列表 */
45 ArrayList<Integer> list = new ArrayList<Integer>();
46
47 int i = 0;
48 int j = 0;
49 int k = 0;
50 while(i<scheduel.tranListForward.size() && j<scheduel.tranListBack.size())
51 {
52 if(scheduel.tranListForward.get(i).arriveTime <= scheduel.tranListBack.get(j).arriveTime)
53 {
54 list.add(k, scheduel.tranListForward.get(i).id);
55 i++;
56 }
57 else
58 {
59 list.add(k, scheduel.tranListBack.get(j).id);
60 j++;
61 }
62 k++;
63 }
64 while(i<scheduel.tranListForward.size())
65 {
66 list.add(k++, scheduel.tranListForward.get(i++).id);
67 }
68 while(j<scheduel.tranListBack.size())
69 {
70 list.add(k++, scheduel.tranListBack.get(j++).id);
71 }
72 return list;
73 }
74
75 /**
76 * 贪心算法搜索出剩余车次中最长的车次链
77 *
78 * @param list 按照FIFO规则排序后的车次的列表
79 * @param scheduel 用于搜索车次链的发车时刻表
80 * @return chain 搜索到的车次链
81 */
82 public static TrainsitChain searchChain(ArrayList<Integer> list,Scheduel scheduel){
83 TrainsitChain chain = new TrainsitChain();
84
85 /** 以当前剩余车次中的第一个车次为该车次链的首个车次*/
86 int index = list.get(0);
87 int len = scheduel.tranListForward.size();
88 if(index >= len ){
89 index -= len;
90 chain.addTransit(scheduel.tranListBack.get(index));
91 }else{
92 chain.addTransit(scheduel.tranListForward.get(index));
93 }
94 list.remove(0);
95
96 /**遍历当前剩余车次搜索到最长车次链 */
97 int i=0;
98 while(i<list.size())
99 {
100 int next = list.get(i);
101 int l = chain.theChain.size();
102 /** 判断该车次是上行还是下行 */
103 if(next >= len)
104 {
105 next -= len;
106 if(scheduel.tranListBack.get(next).getStartTime() >= chain.end){
107 /** 车次链上前后辆车次行驶方向不同 */
108 if(chain.theChain.get(l-1).isForward){
109 chain.addTransit(scheduel.tranListBack.get(next));
110 list.remove(i);
111 }
112 else
113 i++;
114 }
115 else
116 i++;
117 }
118 else{
119 if(scheduel.tranListForward.get(next).getStartTime() >= chain.end)
120 {
121 if(!chain.theChain.get(l-1).isForward){
122 chain.addTransit(scheduel.tranListForward.get(next));
123 list.remove(i);
124 }
125 else
126 i++;
127 }
128 else
129 i++;
130 }
131 }
132 return chain;
133 }
134
135 /**
136 * 读取上行数据
137 * @throws IOException
138 */
139 public static void inputForward(Scheduel scheduel) throws IOException{
140 try{
141 int i = 0;
142 FileInputStream fis = new FileInputStream(forward);
143 InputStreamReader isr = new InputStreamReader(fis);
144 @SuppressWarnings("resource")
145 LineNumberReader lnr = new LineNumberReader(isr);
146 String s = null;
147 while ((s = lnr.readLine()) != null) {
148 int data = Integer.parseInt(s.trim());
149 Transit t = new Transit();
150 t.setID(i);
151 t.setStartTime(data);
152 t.setArriveTime(data+Transit.RUN_FOWARD_TIME);
153 t.setForward(true);
154 if(i!=0)
155 t.setAdjust(scheduel.tranListForward.get(i-1));
156 scheduel.addTransitForward(t);
157 i++;
158 }
159 }catch(FileNotFoundException e){
160 e.printStackTrace();
161 }
162 System.out.println("上行数据: ");
163 System.out.println(scheduel.tranListForward.size());
164 }
165
166 /**
167 * 读取下行数据
168 * @throws IOException
169 */
170 public static void inputBackward(Scheduel scheduel) throws IOException{
171 try{
172 int i = 0;
173 int len = scheduel.tranListForward.size();
174 FileInputStream fis = new FileInputStream(backward);
175 InputStreamReader isr = new InputStreamReader(fis);
176 @SuppressWarnings("resource")
177 LineNumberReader lnr = new LineNumberReader(isr);
178 String s = null;
179 while ((s = lnr.readLine()) != null) {
180 int data = Integer.parseInt(s.trim());
181 Transit t = new Transit();
182 t.setID(i+len);
183 t.setStartTime(data);
184 t.setArriveTime(data+Transit.RUN_BACK_TIME);
185 t.setForward(false);
186 scheduel.addTransitBack(t);
187 if(i!=0)
188 t.setAdjust(scheduel.tranListBack.get(i-1));
189 i++;
190 }
191 }catch(FileNotFoundException e){
192 e.printStackTrace();
193 }
194 System.out.println("下行数据: ");
195 System.out.println(scheduel.tranListBack.size());
196 }
197
198 /**
199 * 根据当前时刻表,不作改动,计算固定行车计划
200 *
201 * @param scheduel 当前时刻表
202 * @return chainList 固定行车计划车次链集合
203 */
204 public static ArrayList<TrainsitChain> creatFixedPlan(Scheduel scheduel){
205 ArrayList<TrainsitChain> chainList = new ArrayList<TrainsitChain>();
206 ArrayList<Integer> trainsitList = new ArrayList<Integer>();
207 trainsitList = sortScheduel(scheduel);
208 while(!trainsitList.isEmpty())
209 {
210 chainList.add(searchChain(trainsitList,scheduel));
211 }
212 System.out.println("车次链数目(最小车队规模): "+chainList.size());
213
214 int n = chainList.size();
215 int i;
216 for( i=0;i<n;i++)
217 {
218 int m = chainList.get(i).theChain.size();
219 System.out.println("车次链:"+ (i+1) +"的组成:");
220 System.out.println();
221 for(int j=0;j<m;j++)
222 {
223 System.out.print(chainList.get(i).theChain.get(j).getStartTime()+"("+chainList.get(i).theChain.get(j).getIsForward()+")"+" , ");
224 }
225 System.out.println();
226 }
227
228 return chainList;
229 }
230
231 /**
232 * 在允许范围内调整发车时刻得到可变行车计划
233 * @param scheduel 行车计划
234 * @param plan 固定行车计划
235 * @return chain 可变行车计划
236 */
237 public static ArrayList<TrainsitChain> creatVariablePlan(Scheduel scheduel, ArrayList<TrainsitChain> plan){
238 sum++;
239 System.out.println("********************** 可变行车计划 *******************************");
240 // System.out.println("********************** 原始发车时刻表 *******************************");
241 // for(Transit t:scheduel.tranListForward)
242 // System.out.println("ID: " + t.getID() + " 发车时间:" + t.getStartTime() );
243 // for(Transit t:scheduel.tranListBack)
244 // System.out.println("ID: " + t.getID() + " 发车时间:" + t.getStartTime() );
245
246 ArrayList<TrainsitChain> chain;
247
248 /** 计算n值,找到最大点 */
249 int last = scheduel.tranListForward.size();
250 for(Transit t:scheduel.tranListForward){
251 for(Transit s:scheduel.tranListBack){
252 if(s.getStartTime() >= t.getArriveTime()){
253 if(s.getArriveTime() >= scheduel.tranListForward.get(last-1).getStartTime())
254 t.setN(scheduel.tranListForward.get(last-1).getID() - t.getID() + 1);
255 for(Transit o:scheduel.tranListForward){
256 if(o.getStartTime() >= s.getArriveTime()){
257 t.setN(o.getID() - t.getID());
258 break;
259 }
260 }
261 break;
262 }
263 }
264 }
265 int size = scheduel.tranListBack.size();
266 for(Transit t:scheduel.tranListBack){
267 for(Transit s:scheduel.tranListForward){
268 if(s.getStartTime() >= t.getArriveTime()){
269 if(s.getArriveTime() >= scheduel.tranListBack.get(size-1).getStartTime())
270 t.setN(scheduel.tranListBack.get(size-1).getID() - t.getID() + 1);
271 for(Transit o:scheduel.tranListBack){
272 if(o.getStartTime() >= s.getArriveTime()){
273 t.setN(o.getID() - t.getID());
274 break;
275 }
276 }
277 break;
278 }
279 }
280 }
281 int max = 0, maxID = 0;
282 for(Transit t:scheduel.tranListForward){
283 if(t.getN() > max){
284 max = t.getN();
285 maxID = t.getID();
286 }
287 }
288 for(Transit t:scheduel.tranListBack){
289 if(t.getN() > max){
290 max = t.getN();
291 maxID = t.getID();
292 }
293 }
294
295 // System.out.println("********************** N值表 *******************************");
296 // for(Transit t:scheduel.tranListForward)
297 // System.out.println("ID: " + t.getID() + " 发车时间:" + t.getStartTime()+ " N 值:" + t.getN() );
298 // for(Transit t:scheduel.tranListBack)
299 // System.out.println("ID: " + t.getID() + " 发车时间:" + t.getStartTime()+ " N 值:" + t.getN() );
300
301 // System.out.println("最大N值:" + max + " " + "最大N值点:" + maxID);
302 /** 调整发车时间 */
303 Transit first;
304 if(maxID < scheduel.tranListForward.size())
305 first = scheduel.tranListForward.get(maxID);
306 else
307 first = scheduel.tranListBack.get(maxID-scheduel.tranListForward.size());
308 Scheduel s = adjustScheduel(scheduel,first);
309 //System.out.println("******************* " + s.tranListBack.get(14-s.tranListForward.size()).getArriveTime() + "*****************");
310
311 /** 搜索车次链 */
312 chain = creatFixedPlan(s);
313
314 /** 判断是否继续搜索 */
315 // System.out.println(" ");
316 // System.out.println(" 可变行车计划: ");
317 // System.out.println("可变计划最小车队规模: " + chain.size());
318 // System.out.println(" ");
319 // System.out.println("可变行车计划:");
320 int n = chain.size();
321 int i;
322 for( i=0;i<n;i++)
323 {
324 int m = chain.get(i).theChain.size();
325 // System.out.println("车次链:"+ (i+1) +"的组成:");
326 // System.out.println();
327 for(int j=0;j<m;j++)
328 {
329 //System.out.print(chain.get(i).theChain.get(j).getStartTime()+"("+chain.get(i).theChain.get(j).getIsForward()+")"+" , ");
330 }
331 //System.out.println();
332 }
333
334 /** 再求解一次调整之后的计算n值,找到最大点 */
335 int last1 = scheduel.tranListForward.size();
336 for(Transit t:scheduel.tranListForward){
337 for(Transit s1:scheduel.tranListBack){
338 if(s1.getStartTime() >= t.getArriveTime()){
339 if(s1.getArriveTime() >= scheduel.tranListForward.get(last1-1).getStartTime())
340 t.setN(scheduel.tranListForward.get(last1-1).getID() - t.getID() + 1);
341 for(Transit o:scheduel.tranListForward){
342 if(o.getStartTime() >= s1.getArriveTime()){
343 t.setN(o.getID() - t.getID());
344 break;
345 }
346 }
347 break;
348 }
349 }
350 }
351 int size1 = scheduel.tranListBack.size();
352 for(Transit t:scheduel.tranListBack){
353 for(Transit s1:scheduel.tranListForward){
354 if(s1.getStartTime() >= t.getArriveTime()){
355 if(s1.getArriveTime() >= scheduel.tranListBack.get(size1-1).getStartTime())
356 t.setN(scheduel.tranListBack.get(size1-1).getID() - t.getID() + 1);
357 for(Transit o:scheduel.tranListBack){
358 if(o.getStartTime() >= s1.getArriveTime()){
359 t.setN(o.getID() - t.getID());
360 break;
361 }
362 }
363 break;
364 }
365 }
366 }
367 int max1 = 0;
368 int maxID1 = 0;
369 for(Transit t:scheduel.tranListForward){
370 if(t.getN() > max1){
371 max1 = t.getN();
372 maxID1 = t.getID();
373 }
374 }
375 for(Transit t:scheduel.tranListBack){
376 if(t.getN() > max1){
377 max1 = t.getN();
378 maxID1 = t.getID();
379 }
380 }
381 //// System.out.println("调整之后最大N:" + max1);
382 //// System.out.println("********************** 调整之后的N值表 *******************************");
383 // for(Transit t:s.tranListForward)
384 // System.out.println("ID: " + t.getID() + " 发车时间:" + t.getStartTime()+ " N 值:" + t.getN() );
385 // for(Transit t:s.tranListBack)
386 // System.out.println("ID: " + t.getID() + " 发车时间:" + t.getStartTime()+ " N 值:" + t.getN() );
387 int newN = 0;
388 if(maxID >= scheduel.tranListForward.size())
389 newN = scheduel.tranListBack.get(maxID-s.tranListForward.size()).getN();
390 else
391 newN = scheduel.tranListForward.get(maxID).getN();
392 System.out.println("调整之后原最大N——new:" + newN);
393 if(max1 > newN ){
394 chain = creatVariablePlan(s,chain);
395 }
396 else{
397 System.out.println("求解结束!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
398 }
399 return chain;
400 }
401
402 /**
403 * 允许范围内调整时刻表缩减单条线路最小车队规模
404 *
405 * @param scheduel 初始时刻表
406 * @param plan 固定行车计划
407 * @param t 开始调整的初始车次
408 * @return adj_scheduel 调整后的时刻表
409 */
410 public static Scheduel adjustScheduel(Scheduel scheduel, Transit t){
411
412 final int RUNTIME_FORWARD = Transit.RUN_FOWARD_TIME;
413 final int RUNTIME_BACK = Transit.RUN_BACK_TIME;
414
415 /** 获取初始车次的ID */
416 int id = t.getID();
417 // System.out.println("查找到的初始车次序号:" + t.getID() +"发车时间:"+ t.getStartTime());
418
419 int a = t.getArriveTime() - t.adjust;
420 // System.out.println("初始车次的最早发车后到达末站的时刻:" + a);
421 int b = 0;
422 if(id >= scheduel.tranListForward.size()){//初始车次位于下行方向
423 // System.out.println("初始值位于上行方向,T(j-1)位于下行方向");
424 id = id - scheduel.tranListForward.size();
425
426 /** 寻找初始车次的第一个可行车次链上的下一个车次 */
427 int num = 0;
428 for(Transit e: scheduel.tranListForward){
429 if((e.getStartTime()+e.getAdjust()) >= a){
430 // System.out.println("下一个可行车次:" + e.getArriveTime());
431 num = e.getID();
432 b = e.getStartTime();
433 if(b >= a){
434 t.setStartTime(t.getStartTime()-t.getAdjust());
435 t.setArriveTime(t.getStartTime() + 15);
436 for(Transit o: scheduel.tranListBack){
437 if(o.getStartTime()+o.getAdjust() >= e.getArriveTime()){
438 if(o.getStartTime() < e.getArriveTime()){
439 o.setStartTime(o.getStartTime()+o.getAdjust());
440 o.setArriveTime(o.getStartTime() + 15);
441 o.adjust = 0;
442 // System.out.println("调整 ID:" + o.getID() + "的值为: " + o.getStartTime() );
443 }
444 }
445 }
446 }
447 else{
448 e.setStartTime(e.getStartTime()+e.getAdjust());
449 e.setArriveTime(e.getStartTime() + 15);
450 e.adjust = 0;
451 // System.out.println("调整 ID:" + e.getID() + "的值为: " + e.getStartTime() );
452 if(t.getArriveTime() < e.getStartTime()){
453 t.setStartTime(t.getStartTime()-t.getAdjust());
454 t.setArriveTime(t.getStartTime() + 15);
455 // System.out.println("调整 ID:" + t.getID() + "的值为: " + t.getStartTime() );
456 }
457 }
458 break;
459 }
460 }
461 }
462 else{//初始车次位于上行方向
463 /** 寻找初始车次的第一个可行车次链上的下一个车次 */
464 int num = 0;
465 for(Transit e: scheduel.tranListForward){
466 if((e.getStartTime()+e.getAdjust()) >= a){
467 num = e.getID();
468 b = e.getStartTime();
469 if(b >= a){
470 t.setStartTime(t.getStartTime()-t.getAdjust());
471 t.setArriveTime(t.getStartTime() + 15);
472 for(Transit o: scheduel.tranListBack){
473 if(o.getStartTime()+o.getAdjust() >= e.getArriveTime()){
474 if(o.getStartTime() < e.getArriveTime()){
475 o.setStartTime(o.getStartTime()+o.getAdjust());
476 o.setArriveTime(o.getStartTime() + 15);
477 o.adjust = 0;
478 }
479 }
480 }
481 }
482 else{
483 e.setStartTime(e.getStartTime()+e.getAdjust());
484 e.setArriveTime(e.getStartTime() + 15);
485 e.adjust = 0;
486 if(t.getArriveTime() < e.getStartTime()){
487 t.setStartTime(t.getStartTime()-t.getAdjust());
488 t.setArriveTime(t.getStartTime() + 15);
489 }
490 }
491 break;
492 }
493 }
494 }
495 return scheduel;
496 }
497 }
498
499 /**
500 * TrainsitChain类
501 *
502 * @author Karel Zuo
503 * @time 2015.6.7
504 * @version 1.0
505 * @description 该类是车次链类,一个车次链由可以被同一辆车执行的所有车次组成
506 */
507 public class TrainsitChain {
508
509 /** 车次链上第一个车次的发车时刻 */
510 float first = 0;
511 /** 车次链上最后一辆车到站时间 */
512 float end = 0;
513 /** 车次链上每一个车次的集合 */
514 ArrayList<Transit> theChain = new ArrayList<>();
515
516 /**
517 * 添加车次到车次链
518 * @param transit 车次
519 */
520 public void addTransit(Transit transit){
521 if(first == 0){
522 first = transit.startTime;
523 end = transit.arriveTime;
524 theChain.add(transit);
525 }
526 else{
527 end = transit.arriveTime;
528 theChain.add(transit);
529 }
530 }
531 }
532
533 public class Scheduel {
534
535 /** 上行时刻表的所有车次集合 */
536 ArrayList<Transit> tranListForward = new ArrayList<Transit>();
537 /** 下行行时刻表的所有车次集合 */
538 ArrayList<Transit> tranListBack = new ArrayList<Transit>();
539
540 /**
541 * @param trainsit 车次对象
542 */
543 public void addTransitForward(Transit tansit){
544 this.tranListForward.add(tansit);
545 }
546
547 /**
548 * @param trainsit 车次对象
549 */
550 public void addTransitBack(Transit tansit){
551 this.tranListBack.add(tansit);
552 }
553
554 /**
555 * @return tranListForward 上行车次集合
556 */
557 public List<Transit> getTranListForeard(){
558 return this.tranListForward;
559 }
560
561 /**
562 * @return tranListBack 下行车次集合
563 */
564 public List<Transit> getTranListBack(){
565 return this.tranListBack;
566 }
567 }
568
569 /**
570 * 车次类
571 *
572 * @author Karel Zuo
573 * @time 2015.6.4
574 * @version 1.0
575 * @description 该类用于表示一个车次的全部信息
576 */
577 public class Transit {
578 /** 上行方向运行时间 */
579 public final static int RUN_FOWARD_TIME = 59;//65;
580 /** 下行方向运行时间 */
581 public final static int RUN_BACK_TIME = 62;//58;
582 /** 车辆运行方向 */
583 boolean isForward;
584 /** 发车时间 */
585 int startTime;
586 /** 到站时间 */
587 int arriveTime;
588 /** 车次ID */
589 int id;
590 /** 发车时间允许调整范围 */
591 int adjust = 0;
592 /** 车次的n值 */
593 int N = 0;
594
595 /**
596 * @return startTime 发车时间
597 */
598 public int getStartTime(){
599 return this.startTime;
600 }
601
602 /**
603 * @return arriveTime 到站时间
604 */
605 public int getArriveTime(){
606 return this.arriveTime;
607 }
608
609 /**
610 * @return id 车次id
611 */
612 public int getID(){
613 return this.id;
614 }
615
616 /**
617 * @return isForward 车辆运行方向
618 */
619 public boolean getIsForward(){
620 return this.isForward;
621 }
622
623 /**
624 * @param adjust 发车时刻允许调整范围
625 */
626 public int getAdjust(){
627 return this.adjust;
628 }
629
630 /**
631 * @param N 该车次的N值
632 */
633 public int getN(){
634 return this.N;
635 }
636
637 /**
638 * @param time 设置的发车时间
639 */
640 public void setStartTime(int time){
641 this.startTime = time;
642 }
643
644 /**
645 * @param time 设置的到站时间
646 */
647 public void setArriveTime(int time){
648 this.arriveTime = time;
649 }
650
651 /**
652 * @param id 车次序号
653 */
654 public void setID(int id){
655 this.id = id;
656 }
657
658 /**
659 * @param isForward 车次运行方向
660 */
661 public void setForward(boolean isForward){
662 this.isForward = isForward;
663 }
664
665 /**
666 * @param t 车次链上相连的前一个车次
667 */
668 public void setAdjust(Transit t){
669 int adjust = 0;//this.startTime - t.getStartTime();
670 if(adjust < 10)
671 adjust = (int)(0.7*adjust);
672 else if(adjust < 20)
673 adjust = (int)(0.5*adjust);
674 else if(adjust < 40)
675 adjust = (int)(0.4*adjust);
676 else
677 adjust = (int)(0.3*adjust);
678 this.adjust = adjust;
679 }
680
681 /**
682 * @param time 设置的发车时间
683 */
684 public void setN(int N){
685 this.N = N;
686 }
687 }