Skip to content

Instantly share code, notes, and snippets.

@amoshyc
Last active August 29, 2015 14:08
Show Gist options
  • Save amoshyc/daf6e8dc03076de4af96 to your computer and use it in GitHub Desktop.
Save amoshyc/daf6e8dc03076de4af96 to your computer and use it in GitHub Desktop.
booking_system_tutor.md

題目

CCU飯店共有N間房間( 0<N<300 ),且提供入住房客指定預入住房號的服務, 如果房客指定房間已有人入住,則提供下一間房間給房客, 亦即原指定房號加一。

但是由於房數眾多,辦理入住櫃檯經常會忘記哪個房間已有人入住。 因此,CCU飯店管理人員決定要請資訊部門幫忙研發一套簡單的軟體, 能夠記錄目前有哪些房間,已有人進住。

Input 第一行數字為房間數,N值。 第二行數字為房客依序指定的房號,以空格分隔,以-1表示輸入結束。 Output 第一行數字為房號001、002、 003、…中間以空格隔開 第二行數字為房間入住情形,若房間已有人入住,則顯示1;若暫無人入住,則顯示0,最後面的0/1後接換行符號,無空格。 第三行數字為房客入住房號順序,以空格格開;最後面的數字後接換行符號,無空格。

Sample Input

10
2 3 9 1 9 9 -1

Sample Output

001 002 003 004 005 006 007 008 009 010
 1   1   1   1   0   0   0   0   1   1
2 3 9 1 10 4

輸入架構

根據題意,我們先處理輸入的部分,得到以下架構:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int N;
    scanf("%d", &N);
	
	int query;
	while (scanf("%d", &query)) {
	    if (query == -1) break;

	}

	return 0;
}

變數與尋找空房

###房間資訊

第 1 種

我們首先需要一個陣列來儲存各個房間有沒有住人的資訊,我個人採取的儲存方法是,若房間i有人住,則 data[i-1] = 1 ,要不然 data[i-1] = 0 ,也就是說

房間 1 的資訊,存在 data 的第 0 項。 房間 2 的資訊,存在 data 的第 1 項。 房間 3 的資訊,存在 data 的第 2 項。 ...

這樣寫,data 陣列的宣告只需要宣告成長度為 N 的陣列。
####第 2 種 當然你要寫成

int data[N+1];

然後捨棄 data[0] 不用。之後

房間 1 的資訊,存在 data 的第 1 項。

房間 2 的資訊,存在 data 的第 2 項。

房間 3 的資訊,存在 data 的第 3 項。

...

這樣當然也可以。(只是之後你要稍為修改我教學中的程式碼)


客人最終住房資訊

另外我們還需要一個陣列來儲存每個客人最後住到哪間房間去了。因為我們不知道總共有幾個客人,但我們知道客人一定不會比 N 還多(程設實習時,我有問過助教,助教說保證不會出現客人人數比房間數多的情況)。

我們想依序將「客人最終住房資訊」存到陣列裡,所以還需要一個變數來記錄「正在詢問的客人,是目前為止第幾個客人(從 0 開始數,這樣可以直接對應到陣列的第幾項)」。

int record[N];
int idx = 0;

尋找空房

當客人詢問 query 號房可不可以住時,有兩種情況:可以住、不可以住,若不可以住的話要尋找可以住的房間。

尋找的規則為:

query+1 可不可以住,若不可以,則

query+2 可不可以住,若不可以,則

query+3 可不可以住,若不可以,則

...

若我們尋找到 第 N 號房,且第 N 號房已經有人住,我們得從第 1 號房開始找起。一直找,直到找到空房為止。因為客人數一定不會大於房間數,所以不用處理找不到空房的情況。

以上的邏輯對應的程式碼可以寫成這樣:

int test = query;

while (data[test] != 0) {
	/*這裡假設你房間資訊的儲存方式是上述的第二種。*/
	test = test + 1;
	if (test == N+1)
		test = 1;
}

若你跟我一樣,房間資訊的儲存方式是第一種,則程式是寫成:

int test = query-1; /*房號 query,對應陣列的第 query-1 項 */

while (data[test] != 0) {
	test = test + 1;
	if (test == N)
		test = 0;
}

或者也可以這樣寫,這種寫法只適用第 1 種儲存方式。

int test = query-1;

while (data[test] != 0) {
	test = (test+1) % N;
}

不管哪種寫法,在迴圈執行完後,test 都會停留在空房上(也是說,data[test] 會是 0)。

也許你會好奇,如果一開始,客人詢問的房號就是空房(data[test] = 0),不是應該寫一個 if 來判斷,我們不需要去尋找空房啊。

你可以仔細看我的 while 迴圈的條件,我是用 while 而不是 do...while ,如果一開始客人詢問的房號就是空房,那麼這個 while 迴圈根本連進入都不會進入。


到目前為止,整個程式碼可以寫成(房間資訊採用第 1 種做法):

#include <stdio.h>
#include <stdlib.h>

int main() {
    int N;
    scanf("%d", &N);

	int data[N];
	memset(data, 0, sizeof(data)); /*初使化陣列*/

	int record[N];
	memset(record, 0, sizeof(record));
	int idx = 0;
	
	int query;
	while (scanf("%d", &query)) {
	    if (query == -1) break;
		
		int test = query-1;
		while (data[test] != 0) 
			test = (test+1) % N;
		
		/*既然找到了空房,就讓客人住進去*/
		data[test] = 1;

		/*這個客人最終住到了陣列的第 test 項,也就是房號 test+1*/
		record[idx] = test+1;
		idx++;
	}

	return 0;
}

輸出

###第一行 補零、寬度為 3 這沒什麼好說的,請自行翻閱文件

這種卡你空格的題目在 uva 上不少見,請一定要將這種方法學起來。(有些題目還有會要你加入空白行之類很麻煩的東西)

因為輸出 不是

001 002 003 

而是

001 002 003

你可以用滑鼠分別反白上面兩行,會發現第一行最後是有一個空白(空格)的,而第二行就沒有。

所以這樣寫絕對會錯:

int i;
for (i=0; i<N; i++)
	printf("%03d ", i+1);
printf("\n");

要處理這個有很多方法,我的做法是:

除了第一項以外,在要輸出的數字前面輸出一格空格。

其它方法,包含有:

除了最後一項,在要輸出的數字後面輸出空格。

雖然說上述的後者比較直覺,但如果你以後持續在寫 uva ,你會發現我們有時很難知道 i 的最後一項是什麼,因為迴圈在中途就 break 了。而 i 的第一項我們幾乎都是知道的。所以我大部分都是用前者的寫法。

int i;
for (i=0; i<N; i++) {
    if (i != 0)
	    printf(" ");
    printf("%03d", i+1);
}
printf("\n"); /*記得換行*/

###第二行 同樣的,輸出的最後 沒有 空格。 觀察一下,應該就會發現一些規則,我找到的是:

除了第一項的數字前面是一個空格,其它項的數字前面都是三個空格。

所以程式碼就很好寫了:

for (i=0; i<N; i++) {
	if (i == 0)
		printf(" ");
	else
		printf("   ");
	printf("%d", data[i]);
}
printf("\n"); /*記得換行*/

###第三行 這行也很簡單,就把我們存在 record 裡的資訊輸出而已,當然還是要注意空格。比較有問題的是我們不知道我們在 record 裡到底存了幾個客人的資訊。

還記得我們之前將資訊存入 record 之後,我們都會將 idx++ ,所以在這一次迴圈結束時,idx 的值是已經指向下一個該存入資訊的位置了。當整個迴圈結束後,idx 的值也相當於是客人的人數。

例如,假設 while 迴圈執行 6 次,並在第 6 次時,一進入迴圈馬上就跳出。在 while 第 5 次迴圈結束時,idx 變成 5。第 6 次時,沒有更新到 idx 的值,所以在整個迴圈結束時,idx 就是 5 ,也就是客人的人數。

所以第三行我們直接這樣寫就可以了:

for(i=0; i<idx; i++) {
	if (i != 0)
		printf(" ");
	printf("%d", record[i]);
}
printf("\n"); /*記得換行*/

第一次使用 markdown 寫這麼長的文章,比起之前那樣寫,現在這樣寫你們感覺有比較好嗎?


Written with StackEdit.

By Yu-Cheng Huang Nov. 4, '14

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment