【刷題筆記】火車購票-----java方案


問題描述
請實現一個鐵路購票系統的簡單座位分配算法,來處理一節車廂的座位分配。
  假設一節車廂有20排、每一排5個座位。為方便起見,我們用1到100來給所有的座位編號,第一排是1到5號,第二排是6到10號,依次類推,第20排是96到100號。
  購票時,一個人可能購一張或多張票,最多不超過5張。如果這幾張票可以安排在同一排編號相鄰的座位,則應該安排在編號最小的相鄰座位。否則應該安排在編號最小的幾個空座位中(不考慮是否相鄰)。
  假設初始時車票全部未被購買,現在給了一些購票指令,請你處理這些指令。
樣例說明
輸入格式
  輸入的第一行包含一個整數n,表示購票指令的數量。
  第二行包含n個整數,每個整數p在1到5之間,表示要購入的票數,相鄰的兩個數之間使用一個空格分隔。
輸出格式
  輸出n行,每行對應一條指令的處理結果。
  對於購票指令p,輸出p張車票的編號,按從小到大排序。
樣例輸入
4
2 5 4 2
樣例輸出
1 2 1) 購2張票,得到座位1、2。
6 7 8 9 10 2) 購5張票,得到座位6至10。
11 12 13 14 3) 購4張票,得到座位11至14。
3 4 4) 購2張票,得到座位3、4。    
  
---------------------------------------------------------------請思考的分割線----------------------------------------------------------------------

  讀者看到這里的時候,想必心里已經有自己的想法了。無論可行性如何,有想法才是最重要的。接下來我們來看一下這個問題的解決思路吧。(個人能力有限,所以貢獻的算法也難免局限,如果大家有更好的想法,歡迎討論)

  首先,看到問題的時候第一思路是建立一個數組來記錄100個座位的占用情況,對於每一次的購票行為,只需要對數組進行遍歷,找到滿足要求的位置並占用即可。當然這種方法的缺陷也很明顯,每一次的購票行為都需要對數組進行遍歷,而且由於每一排有5個座位的限制,所以在遍歷的時候仍然要考慮連續的座位是否在同一排中,這無疑會增加算法的復雜性。

  進一步想,既然題目的座位是20排,那我們可以直接選擇二維數組作為我們記錄占用情況的數據結構。針對二維數組而言,我們只需要按行遍歷,對於每一行判斷是否可以容納本次的購票人數。這種方法的遍歷情況跟上一個方法是一樣的,優勢在於每一次的子數組長度都是5,不需要另行判斷。

  上面的方法都局限在同一個問題,即對座位數組的反復遍歷。尤其是對於那些已經占用的座位,每一次的遍歷都是白白地消耗時間,如果,(敲黑板,重點來了)對於已經被占用的位置,我們可以減少訪問,那么我們的運行時間就可以縮短!!!

  針對上面的兩種思路我們來進行改進,我們先從一維數組開始考慮(因為二維數組的想留給讀者自己試驗)。在購票過程中,我們會盡量地把同一批客戶安排在連續的同一排座位。那么我們在每次安排座位的時候,在被占用的數組中標示連續占用的座位數,這樣的話,在我們遍歷的時候就可以直接利用這個數字跳過這段連續的區域,減少訪問次數。

  看完上面這段,讀者可能對方法還是很疑惑。語言描述實在是不夠直觀,我們不妨看一下示意圖。

          

  如果讀者看圖已經明白了原理,不妨先去實現一下。如果還是覺得抽象,我們就來細細地看圖說話吧。

  上圖顯示的就是示例中的購票過程,首先將數組seats初始化為0,表示座位空置。

  第一次購票2張,占用位置(數組片段)是1、2,把seats[1]的數字置為2,表示由此開始的連續兩個座位被占用。等到遍歷數組時,在這個位置可以對下標進行+2操作,直接跳過這一段被占用的座位。

  第二次購票是5張,從頭開始遍歷數組,訪問第一個位置,被占用且數字為2,則跳轉到1+2=3號位置,3號座位為0表示空置,但是3--5之間只有三個空位,不能容納5個人,所以跳轉到下一排,即6號位置,6號位滿足要求,在此處落座並更改seats[6] = 5。

  第三次購票是4張,依然從頭開始,1號位非0,跳轉至1+2=3號位;3號位為0,但是空間不足,跳轉至6號位;6號位非0,跳轉至6+5=11號位;11號位為0且空間足夠,落座並更改seats[11] = 4。

  第四次購票是2張,遍歷過程如上,1號位非0,轉至1+2=3號位;3號位為0且空間足夠,落座並更改seats[3]=2。

  到此為止,例程部分的購票已經結束。如果某次購票行為中發現沒有足夠的連續空位,就要選擇散座,即重新從頭開始遍歷,並且每次只坐一個人。方法同上。

  總結一下,在這個版本的算法中,我們合理利用了開辟的數組,記錄了被連續占用的段落長度,從而減少了遍歷的次數,好像已經前進了一步。但是這個算法仍然可能需要進行兩次遍歷,即第一次找不到連續座位然后重新找散座。因為題目中的要求是先盡量連續分配,失敗則分配散座,所以兩次遍歷操作是難免的。

  考慮到以上的情況,再來想一想能不能在遍歷過程中再精簡一些。

---------------------------------------------------------------請思考的分割線----------------------------------------------------------------------

  

  仔細分析一下,上面的過程中對於每一排座位,是在發現空位之后才去判斷空位數是否足夠。從二維數組的角度考慮一下,如果每一行的第一個位置標示了這一排已經坐下的人數x,那么我們就可以很直接的通過5-x得到空余的座位。這樣的話我們就不必要先跳轉到空位,而可以直接判斷是否在這一排落座,如果選擇落座的話,則利用排首坐標+x跳轉至座位。
  相比之下,二維數組的情況跟一維是相似的,甚至更簡單,我們在每一行的第一個位置記錄下本行已經被占用的座位數,這樣的話每次只需要訪問seats[*][1]的數字,就可以得知該行是否可以坐並且可以直接找到空位,落座的時候也只需要讓seats[*][1]加上本次坐下的人數。

PS:讀者如果注意到上面seats[*][1]里的*,應該明白其實完全可以只用一個20位的數組解決。哇塞,進步好大啊!!問題不難,讀者請動手試試吧。(注意,文中的數組起始下標是1,請根據實際情況修正)

 PPS:俗話說得好,talk is cheap,show me the code。下面貼上對於一維數組的相對比較復雜的算法實現。大家試着實現其它的吧。

 1 Scanner fin = new Scanner(System.in);      //有一些語句是為了對應提交題目的格式,讀者自動選擇有價值的部分參觀
 2 int N = fin.nextInt();
 3         
 4 int [] seat = new int[100];
 5         
 6 for(int i=0;i<N;i++){
 7         int num = fin.nextInt();
 8         int pos = 0;
 9         while(pos < 100){
10             if(seat[pos] == 0){
11                 if(pos%5 + num <= 5) break;
12                 pos = pos + 5 - pos%5;
13             }else{
14                 pos += seat[pos];
15             }
16         }
17         if(pos < 100){
18             seat[pos] = num;
19             while(num > 0){
20                 String cc = Integer.toString(++pos);
21                 System.out.print(cc + " ");
22                 num --;
23             }
24         }else{
25             pos = 0;
26             while(num > 0){
27                 if (seat[pos] == 0){
28                     String cc = Integer.toString(pos+1);
29                     System.out.print(cc + " ");
30                     seat[pos++] = 1;
31                     num--;
32                 }else{
33                     pos += seat[pos];    
34                 }
35             }
36         }
37         System.out.println("");
38  }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM