本書 本 - 碁峰資訊epaper.gotop.com.tw/pdfsample/acl036300.pdf前言 - v -...

22
前言 我們長期從事資料結構教學和競賽培訓,教學實踐使我們產生了對資料結構課程的教學模 式進行改革的想法: 1在課程中需要增加思考方式和解題策略的引導,引導學生思考各類資料結構的本質特 徵是什麼;面對問題為什麼要採用這樣的資料結構而不宜採用那樣的資料結構;當有 多個資料結構可用時,怎樣權衡時間複雜度、空間複雜度、程式設計複雜度和思維複 雜度四個因素,尋找最合時宜的來使用,將「知識導向」與「智慧導向」真正結合起 來。 2在課程中需要引入案例教學,透過模擬或者重現現實生活中的一些場景,讓學生置身 問題情境之中,透過思考、討論和上機實作來學習。傳統教學將資料結構「束之高閣」, 在理論教學和筆試上兜來兜去,可能會使學生渾然不知資料結構在現實生活中究竟有 什麼用處,懵懵懂懂,最終失去了學習的意義。「紙上得來終覺淺,絕知此事要躬行」。 案例教學則是一種以問題和動手程式設計驅動學習的方式:將知識置於問題情境和實 踐過程之中,將枯燥乏味變為生動活潑。學生拿到試題後,先進行審題,然後溫習或 查閱各種他認為必要的資料結構知識,這無形中激發了他們的求知欲望,加深了他們 對知識真諦的理解。捕捉到相關的理論知識後,學生還要經過縝密思考和動手程式設 計,使之變為解決問題的程式方案。這個「認識-實踐-再認識-再實踐」的過程, 應視為知識理解上的一種提升,知識學習與應用能力之間的一種轉變和昇華。

Upload: others

Post on 04-Jan-2020

4 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

前言

我們長期從事資料結構教學和競賽培訓,教學實踐使我們產生了對資料結構課程的教學模

式進行改革的想法:

1) 在課程中需要增加思考方式和解題策略的引導,引導學生思考各類資料結構的本質特

徵是什麼;面對問題為什麼要採用這樣的資料結構而不宜採用那樣的資料結構;當有

多個資料結構可用時,怎樣權衡時間複雜度、空間複雜度、程式設計複雜度和思維複

雜度四個因素,尋找最合時宜的來使用,將「知識導向」與「智慧導向」真正結合起

來。

2) 在課程中需要引入案例教學,透過模擬或者重現現實生活中的一些場景,讓學生置身

問題情境之中,透過思考、討論和上機實作來學習。傳統教學將資料結構「束之高閣」,

在理論教學和筆試上兜來兜去,可能會使學生渾然不知資料結構在現實生活中究竟有

什麼用處,懵懵懂懂,最終失去了學習的意義。「紙上得來終覺淺,絕知此事要躬行」。

案例教學則是一種以問題和動手程式設計驅動學習的方式:將知識置於問題情境和實

踐過程之中,將枯燥乏味變為生動活潑。學生拿到試題後,先進行審題,然後溫習或

查閱各種他認為必要的資料結構知識,這無形中激發了他們的求知欲望,加深了他們

對知識真諦的理解。捕捉到相關的理論知識後,學生還要經過縝密思考和動手程式設

計,使之變為解決問題的程式方案。這個「認識-實踐-再認識-再實踐」的過程,

應視為知識理解上的一種提升,知識學習與應用能力之間的一種轉變和昇華。

Page 2: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

-

iv -

提升程

基於

程式

後作

問題

而且

「學

本書

程式設

於上

式設

作為

題背

且所

學以

書試題

POJ

北京

http

ZOJ

浙江

http

UVA

UVA

http

http

Ura

Ura

http

SGU

SGU

http

設計的

上述想

設計競

為學習

背景,而

所編的

以致用

題的

J

京大學

://poj

J

江大學

://acm

A

A 線上

://uv

://liv

l

l 線上

://acm

U

U 線上

://acm

的資料

想法

競賽和

習資料

而且

的程式

用」的

的線

學線上

j.org/

學線上

m.zju

上評

a.onl

vearch

上評測

m.tim

上評

m.sgu

料結

,我們

和其他

料結構

且在相

式的

的目的

線上評

上評測

/

上評測

u.edu

測系

lineju

hive.o

測系統

mus.ru

測系

u.ru/

結構力

們近

他程

構知

相關網

正確

的。

評測

測系

測系

u.cn/o

系統

udge.

onlin

u/

系統

近年來

程式設

知識的

網站上

確性和

測系統

online

org/

nejudg

來開設

設計競

的實驗

上都

和效

統主

ejudg

ge.or

設了

競賽

驗與實

都有試

率也

主要

ge/

rg/

「資

中的

實作

試題的

也可以

要有:

資料結

的典型

作案例

的線上

以透過

結構實

型試題

例。這

上測

過相

實驗與

題分

這些試

測試。學

相關網

與實

門別

試題

學生

網站上

實作」

別類,

不僅

生不僅

上的

課程

精選

僅為相

僅可以

測試

程,

選了其

相關知

以帶著

試系統

並將

其中

知識

著問

統得到

將 AC

中 204

識建立

題學

到即

CM 國

4 道試

立了豐

學習資

即時檢

國際大

試題

豐富有

資料結

檢驗

大學

,翻

有趣

結構

,達

學生

翻譯

趣的

構,

達到

Page 3: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

前言

- v -

本書按照資料結構的知識結構和循序漸進的原則,共分四個 Part(基本能力的程式設計實

作、線性資料結構的程式設計實作、層次類非線性串列的程式設計實作、群聚類非線性串

列的程式設計實作)14 個章節。每個章節為相關資料結構知識提供了大量的實作範例,並

且建立了相關的試題庫,其中實驗範例 68 道,題庫試題 136 道。每個實作範例不僅有知

識要點闡述和詳盡的試題解析,還列出了寫 有詳細注釋的參考程式;題庫中的所有試題

無論難易,都有清晰的提示。教師既可以將實作範例作為開設資料結構實作課程的教材,

也可以從相關題庫中挑選資料結構實作課程的作業、考題或指導 ACM 集訓活動的培訓資

料。每道題都注明了試題來源和線上測試系統,考慮到網站更新給讀者學習帶來不便的可

能情況,本書還整理了所有試題的英文原版描述和大部分試題的測試資料等資料的檔案供

讀者下載。我們之所以這樣做,就是力圖建構一個盡可能豐富、實用和長效的資料結構實

驗與實作課程資源庫。

需要說明的是,本書是在復旦大學 ACM 集訓隊長期活動的基礎上累積而成的。阿拉法特

居來提、姚哲雲、張昊等同學精心編寫了所有程式,每道程式都透過了嚴格的測試驗證,

其中一些程式經多次修改,精益求精。這些同學為本書的出版付出了有不心血和貢獻。在

此,向他們表示由衷的感激。另外,衷心感謝復旦大學電腦學院 2006、2007、2008 級同

學在使用本書講義過程中提出的寶貴意見和建議。

由於時間和能力所限,書中若有缺點和不足之處,熱忱歡迎學術界同仁和讀者賜教指正。

如果你在閱讀中發現了問題,請透過書信或電子郵件告訴我們,以便及時整理成勘誤表放

在本書的專門網站上,供廣大讀者查詢更正。我們更期望讀者對於本書提出建設性的意見,

以便再版時改進。我們的聯繫方式是:

通信地址:上海市邯鄲路 220 號復旦大學電腦科學技術學院 吳永輝

郵編:200433

E-mail:[email protected]

Page 4: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

-

vi -

提升程

復旦

Co

算機

《資

以教

程式設

作者

吳永輝

旦大

unci

ACM

機研

資料

教練

ACM

2011

2010

2009

2008

2007

2006

2005

2004

2003

2002

每年

其他

[1]

[2]

設計的

者簡

大學計

l Chi

M-IC

研究與

料通信

練身份

M/IC

1ACM

0ACM

9ACM

8ACM

7ACM

6ACM

5ACM

4ACM

3ACM

2ACM

年獲得

他程式

百度

兩次

Goog

2006

的資料

簡介

博士

計算

ina)

CPC

與發展

信與網

份連續

CPC 程

M 世界

M 世界

M 世界

M 世界

M 世界

M 世界

M 世界

M 世界

M 世界

M 世界

得亞洲

式設計

之星程

冠軍

gle Co

,200

料結

機科

)成員

世界

展》、

網路

續帶隊

程式設

界總決

界總決

界總決

界總決

界總決

界總決

界總決

界總決

界總決

界總決

洲區預

計競賽

程式設

(200

ode Ja

08,2

結構力

科學與

員,復

界總決

、《軟

》和

隊進

設計

決賽第

決賽第

決賽第

決賽第

決賽第

決賽第

決賽第

決賽第

決賽第

決賽第

預賽冠

設計大

09,2

am:

2011

與工

復旦

決賽,

軟體學

和《資

進入 A

競賽

第 27

第 11

第 14

第 13

第 26

第 39

第 6 名

第 15

第 13

第 7 名

軍。

大賽

2011

三次

程系

大學

,並取

學報》

資料通

ACM

),兩

入圍現

系副教

學 AC

取得世

》、以

通信

M-ICP

兩次亞

現場決

教授

CM 程

世界

以及重

、計

PC 世

軍(

決賽

授,A

程式設

界第 6

重大

計算機

世界總

2005

,最好

ACM

設計

6 名的

大學術

機網路

總決

,200

好成績

-ICP

計競賽

的佳績

術會議

路與

賽,

09),

績 201

PC 中

賽隊教

績。他

議上發

開放

競賽

每年

11 全

中國

教練

他的

發表

放系統

賽的主

年多人

球第

賽區

。作

主要

表過多

統》。

主要

人入圍

6,中

區指導

者自

要研究

多篇論

獲獎

圍現場

中國選

導委

自 200

究方向

論文

獎情況

決賽

選手名

員會

01 年

向為

,參

況:

名列第

會(A

年起連

資料

參與翻

第 1。

ACM

連續帶

料庫,

翻譯出

M-ICP

帶隊

在《

出版

PC

隊進

版了

Page 5: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

前言

- vii -

作者簡介

王建德

著名的資訊學奧林匹克競賽金牌教練,國務院特殊津貼專家,中學特級教師。他所輔導的

學生在國際奧林匹克競賽(IOI)中獲得 7 金、3 銀、2 銅的優異成績,先得出版了 24 本

關於程式設計和演算法的學術著作。其中《實用演算法的分析與程式設計》廣受好評,該

書長期以來是各類程式設計競賽的必備教材。

Page 6: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

C應

直接

性串

陣列

若陣

在陣

裝置

存取

的結

串中

以陣

或非

日期

四個

設計

Ch應用

存取

列。

是儲

列元

列中

,在

任意

構。

的某

列為

線性

計算

典型

實作

ha用

取類的

陣列

儲存於

元素不

中,資

在陣列

意一個

字串

某一字

為代表

性結構

算、高

型範例

作。

ap用直

的線性

列就是

於連續

不再有

資料元

列中存

個元素

串、記

字元

表的直

構類型

高精度

例,下

pte直接

性串

是這

續儲

有分

元素

存取

素的

記錄

;可

直接

型的

度數

下面

er接

列,

類資

存空

量,該

的下

一個

時間

、檔

以按

存取

資料

的表

首先

r 0接存

指的

資料結

空間中

該序

下標間

個資料

間都為

檔案也

按記錄

取類線

料物件

表示與

先圍繞

04存取

的是可

結構

中的相

序列叫

間接反

料元素

為 O(

也都屬

錄號檢

線性串

件,都

與處理

繞這四

4

取類

可以直

相同

叫一維

反映

素只

(1)。

屬於

檢索

串列

都可

理、

四個

直接

型的

資料

維陣列

了資

要透

從這

直接

記錄

是程

採用

多項

問題

類的

接存取

的代表

料類型

列;若

資料元

透過下

這個意

接存取

錄集合

程式設

用該儲

項式的

題展開

的線

取某一

表。

型的資

若資

元素的

下標計

意義上

取類線

合或檔

設計中

儲存方

的表示

開程式

一指定

資料

料元

的儲

計算

上講

線性

檔案

中使

方式

示與

式設

定項

元素

元素為

存位

它的

,陣

串列

中的

處理

計實

性串

項而無

素的集

為陣列

位址,

的儲存

陣列的

列,例

的某一

多的

理、數

實作,

串列

無須先

集合

列,則

,而電

存位址

的儲存

例如

一記錄

的資料

數值矩

,然後

先存

,是

則稱

電腦

址就

存結

,可

錄。

料結

矩陣

後再

列程

取其

一種

該元

記憶

行了

構是

以按

構,

的運

展開

程式

其前驅

種定長

元素為

憶體是

了,因

是一個

按下標

無論

運算是

開字串

驅或後

長的線

為多維

是隨機

因此在

個可直

標直接

論是線

是陣列

串處理

後繼

線性

維陣

機存

在陣

直接

接存

線性

列應

理的

設計

的線

串列

列。

取的

列中

存取

取字

結構

用的

程式

列。

Page 7: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

-

4-2

4

提升程

-

4.

日期

1)

2)

由於

需要

數字

看兩

.1.

日曆

按照

400

200

哪月

輸入

輸處

輸出

程式設

1

期由

於日

要對

字對

兩個

1

曆是

、月

照目

0 整除

00 和

月哪

輸入包處理

對每個「Day「Thu

設計的

年月

一個

分別使

特徵不

元素一

直接按

性串列

期的

對應的

對應。

個實例

C

是用於

、年

前國

除的

和 240

哪日星

包含若。可以

個測試yOfWursd

的資料

陣列

月日表

個結構

使用記

不僅充

一個接

按下標

列。

的計算

的英文

計算

例。

Cal

於表述

年、世

國內使

的年是

00 是

星期幾

若干行以假設

試樣例Weekday」

料結

表徵

構陣列

記錄年

充分展

接一個

標存取

算和

文表述

算得出

en

述時

世紀都

使用的

是例外

是閏年

幾。

行,每設輸出

例輸出」必

,「Fr

結構力

。日

列儲

年月

展現

個排

取日

日曆

述,

出日

da

間的

都是

的陽

外,它

年。給

每行包出的年

出一行須是riday

應用

期類

儲存,

日的

現了線

排列)

期元

曆的轉

因此

期資

r

的系統

是日曆

陽曆,

它們不

給定

含一個份不會

行,該下列y」或

用一

類型的

陣列

的 3 個

線性串

、「均

元素。

轉換需

此可將

資料後

統,從

曆系統

閏年

不是

西元

個正整會超過

行包含常數

或「Sa

一:

的題

列元素

個整數

串列

均勻性

。因此

需要在

將這些

後,以

從小

統表述

年被定

是閏年

元 200

整數,過 99

含對應中的aturd

目可

素為

數陣

的「

性」

此儲

在表

些英

以它

時到

述時

定義

年。例

00 年

,表示99。

應的日一個day」

日期

可以用

為一個

陣列。

有限

(各

存日

表徵日

英文表

為下

到分鐘

時間的

義為能

例如:

年 1 月

示 200

日期和:「S

」。

期計

用陣列

個含年

將輸

限性」

日期

日期元

日期的

表述設

下標

鐘,從

的單位

能被 4

170

月 1 日

00 年

和星期Sunda

計算

列作為

年月

輸入的

」(日

元素

元素的

的資

設成一

,即可

從月

位。

4 整除

0、18

日後

年 1 月

期幾。ay」,

算的

為資

日資

的日

日期元

素的類

的線

料間

一個

可從

到日

除的

800、

的天

月 1 日

格式為,「Mo

的實

資料結

資訊的

期透

元素的

類型相

性串

間進行

個線性

從表中

日,

的年份

、190

天數,

日後的

為「Yonday

實作

結構

的結構

透過線

的個

相同

串列是

行運算

性的字

中找出

後從

份,但

00 和

你的

的天數

YYY y」,

作範

,儲

構體

線性

個數有

同),而

是一種

算,而

字串常

出對應

從年

但是能

和 210

的任務

。輸入

Y-MM「Tue

範例

存方

串列

有限)

而且

種典

而輸

常數

應的

份到

能被

00 不

務是

入 後

M-DD esday

方式一

列組織

)、「有

且表長

典型的

輸出的

數表,

的字串

到世紀

被 100

不是閏

是列出

後一行

Dayy」,

一般有

織起來

有序

長相對

的直接

的月份

其下

串。我

紀。術

0 整除

閏年,

出這一

行是 -

yOfWe「Wed

有兩

來,其

序性」

對固定

接存取

份或週

下標與

我們不

術語

除而不

,而 1

一天是

1,程

eek」dnes

種:

其結

(日

定,

取類

週一

與日

不妨

語小時

不能

1600

是哪

程式不

, 其day

結構

類線

一般

妨來

時、

能被

0、

哪年

不必

其中」,

Page 8: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

Chapter 04 應用直接存取類的線性串列程式設計

- 4-3 -

樣例輸入: 樣例輸出:

1730 1740 1750 1751 -1

2004-09-26 Sunday 2004-10-06 Wednesday 2004-10-16 Saturday 2004-10-17 Sunday

試題來源:ACM Shanghai 2004 Preliminary

線上測試:POJ 2080,ZOJ 2420

▼解題與分析

首先設計兩個函數:

1) days_of_year(year):計算 year 年的天數。若 year 能被 4 整除,但不能被 100 整除,或

者 year 能被 400 整除,則 year 年是閏年,全年 366 天;否則 year 年是平年,全年 365

天。

2) days_of_month(month,year):計算 year 年 month 月的天數。在 month=2 的情況下,若

year 年是閏年,則該月天數為 29 天,否則該月天數為 28 天;在 month=1,3,5,7,

8,10,12 的情況下,該月天數為 31 天;在 month=4,6,9,11 的情況下,該月天數

為 30 天。

我們以 2000 年 1 月 1 日(星期六)為基準,按照如下方法計算 n 天後的年、月、日和星

期的資訊。設 year、month、day 為年、月、日變數,wstr 為星期幾的字串常數。初始時

year=2000,month=1,day=1。

首先計算星期幾:以 2000 年 1 月 1 日星期六為每週週期的開始,即 wstr[0..6]={"Saturday",

"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"}。顯然 wstr[n % 7] 即為

2000 年 1 月 1 日的 n 天後的星期幾資訊。

接下來計算 year:在 n > 0 的情況下,若 n ≥ days_of_year(year),則 n -= days_of_year(year),

++year,直至 year 大於 n 為止,此時的 n 為 year 內的天數。

後計算 month 和 day:在 n > 0 的情況下,若 n ≥ days_of_month(month, year),則 n -=

days_of_month(month, year),++month,直至 year 年 month 月的天數大於 n 為止,此時的

n 為 year 年 month 月內的天數。顯然 day = n+day,n=0。

Page 9: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

-

4-4

提升程

-

#uc

i

i

i

程式設

參考程

#incusincons"Thu

int {

i r

}

int {

i

is }r

}

int {

icw

設計的

程式

cludeng nast chursda

days

if (y

retur

days

if (m

int dswitc

retur

main

int ncin >while

的資料

e <iamesphar way",

s_of_

year ret

rn y

s_of_

montret

d; ch (cascas

rn d

n(vo

n; >> ne (n intweayeamondaywhi } //按cou

料結

ostrpacewstr"Fr

_yea

% 1turn ear

_mon

h ==turn

montse 1:se 10

d brded

;

id)

; //>=

t yeaak = ar = nth =y = 1le

if

}

}

}

按照格ut <<

<<

結構力

ream>e std[][2riday

ar(in

100 =yea% 4

nth(i

= 2)day

th) : ca0: c= 3reakefau= 3

/輸入0) ar, mn % 200= 1;1; (n) f (n

els

els

格式要< ye< (d

>d;20] =y"};

nt y

== 0r % ==

int

s_of

{ se 3ase 1;k; ult:0;

入第 1{ mont7; 0;

{ n >= n -=++yee ifn -=++moe { day n =

要求輸ar <day <

= {"S

year)

0) 400 0 ?

mont

f_yea

3: ca12:

個測

th, d//為

day= daear; f (n = daonth//+= 0;

出對應<< '-< 10

//

Satu /

) /

== 366

th,

ar(y

ase

試用例

day,為方便

s_ofys_o

>= ys_o; 後確n;

應的日-' <? "

//預編//使用rday//星期

//返回

0 ? : 3

int

year)

5: c

wea便起見

f_yeaof_ye

daysof_mo

確定日

日期和< (m0"

編譯命用 C+y", "期幾的

回 ye

366 365;

year

) ==

case

ak; ,將星

ar(year(

s_ofonth

和星期month: ""

命令++標準"Sun的字串

ear 年

: 3

r) /

366

7:

星期六

year)year

_monh(mon

期幾h < ) <<

準程式day"

串常數

年的天

365;

/返回

6 ? 2

case

六(20

) { r);

nth(mnth,

10 ?< day

式庫中", "M

天數

回 yea

29 :

e 8:

000 年

//先

montyea

? "0y <<

中的所Mond

ar 年

28;

年 1 月

先列舉

th, yar);

" : < '

有識別ay",

年 mon

;

月 1 日

舉到指

year

"") ' <<

別字 "Tu

th 月

日為星

指定年

r)) {

<< wst

uesd

月的天

星期六

{ //再

monttr[we

ay",

天數

)作為

再列舉

th <eak]

"We

為一個

舉到指

< '- <<

edne

個星期

指定月

-' end

sday

期的開

月份

dl;

y",

Page 10: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

Chapter 04 應用直接存取類的線性串列程式設計

- 4-5 -

cin >> n; //輸入下一個測試用例 } return 0; }

4.1.2 What Day Is It?

現在使用的日曆是從古羅馬時期演變來的。Julius Caesar 發明了日曆系統,後來被稱為

Julian 曆。在這個系統中,4 月、6 月、9 月和 11 月有 30 天;非閏年 2 月有 28 天,在閏年

2 月則有 29 天;其他月份有 31 天。除此之外,在這個日曆系統中,閏年是每 4 年 1 次。

這是因為古羅馬的天文學家計算出 1 年有 365.25 天,因此在每 4 年之後,需要添加額外的

一天以保持季節的正常。為此,每 4 年要在一年中增加額外的一天(2 月 29 日)。

Julian 曆規則:如果年份是 4 的倍數,則該年是閏年,即有額外的一天(2 月 29 日)。後

來天文學家們注意到,一年不是 365.25 天,而是接近 365.2425 天。因此在 1582 年,羅馬

教皇 Gregory 下令改革曆法,新修訂後的曆法稱為 Gregorian 曆,即西曆。Gregorian 曆(西

曆)規則:年份是 4 的倍數是閏年,但如果這一年是 100 而不是 400 的倍數,則不是閏年。

為了彌補在那個時候已經造成的季節與日曆的差異,日曆被挪後了 10 天:1582 年 10 月 4

日被宣佈為 10 月 15 日。

大英帝國(當然那時還包括美國)當時沒有改用西曆。一直到 1752 年才將 9 月 2 日宣佈

為 9 月 14 日(延遲改變的原因是亨利八世和教皇的關係交惡)。

請編寫一個程式,對美國使用的西曆日期進行轉換,並輸出是星期幾。

輸入

輸入是一個大於零的正整數序列,每行 3 個代表日期的整數,一個日期一行。日期的格式 是「月 日 年」,其中月是 1 至 12 的正整數(1 表示 1 月,12 表示 12 月…等等),日是一個 1 至 31 的正整數,而年則是一個正整數。

輸出

輸出按照樣例中列出的格式列出輸入的日期和星期幾。在美國使用的日曆中無效的日期或不存在的日期,則要輸出一個指出無效日期的錯誤訊息。輸入以三個 0 結束。

樣例輸入: 樣例輸出:

11 15 1997 1 1 2000 7 4 1998 2 11 1732 9 2 1752 9 14 1752 4 33 1997 0 0 0

November 15, 1997 is a Saturday January 1, 2000 is a Saturday July 4, 1998 is a Saturday February 11, 1732 is a Friday September 2, 1752 is a Wednesday September 14, 1752 is a Thursday 4/33/1997 is an invalid date.

Page 11: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

-

4-6

提升程

-

試題

線上

由於

c c

一旦

期的

的旗

&&

整除

我們

有了

一個

程式設

題來源

上測試

解題

於在

cons=

cons=

旦確

的字

year

旗標

& day

old=

除,

們可

isLe

days

days

vali

(1

在 1

了以

個日

計算

透過

資訊

設計的

源:A

試:Z

題與

在輸出

st ={"Sust ={"",

確定月

字串。

r、m

標,即

y <=

=true

或者

可以根

eap(y

s_of_

s_of_

d(mo

≤mo

1752

以上基

期,

算目前

過執行

訊,並

的資料

ACM

ZOJ 12

與分析

出的轉

chaundacha

, "Ja "S

月份和

month

即 old=

2))

e 且 y

者能被

根據 o

year, o

_year

_mon

onth,

onth≤

年 9

基礎

按照

前日期

行 val

並繼續

料結

Pacif

256,

轉換後

ar wsy","ar msanuaepte

和星期

h 和 d

=(y

year

被 40

old 設

old)

r(year

nth(m

day,

≤12)

月 3

,便可

照下述

期是否

lid(m

續讀下

結構力

fic No

UVA

後的

str["Mondstr[ary",ember

期的

day 為

year <

能被

00 整

設計

,判斷

r, old

month

year,

) &&

3 日至

可以

述方

否屬

month

下一

orthwe

A 602

的日期

][maday"][ma, "Fer",

的整數

為目

< 175

被 4 整

整除,

4 個

斷 ye

d),計

h, yea

,old)

&(1

至 13

以展開

方式進

於 17

h, day

個日

est 19

期中

axs] ,"Tuaxs] ebru"Oct

數,將

前日

52 ||

整除

則 y

個函數

ear 是

計算 y

ar, isL

,判

1≤da

日的

開主演

進行轉

752 年

y, yea

期;

997

,月份

/uesd

/uary"tobe

將其作

日期的

(yea

,則

year

數:

是否是

year

Leap(

別 ye

ay≤da

的範圍

演算法

轉換

年 9 月

ar,old

否則

份和

//表示ay",//表示", "Mr",

作為

的年月

r ==

則 yea

是閏

是閏年

年的

(year,

ear 年

ays_o

圍內)

法了

月 2

d) 函數

則計算

和星期

示星期"Wed

示月份Marc"Nov

為對應

月日

1752

ar 是

閏年

年。

的天數

, old)

年 mo

of_m

),則

了:反

日前

數判別

算累計

期是字

期幾的dnes份的字ch", vemb

應字串

日整數

2 &&

是閏年

數。

)),計

onth 月

month

有效

反覆讀

的日

別該

計西元

字串

的字串sday"字串常"Apr

ber",

串常數

數;o

& mo

年;否

計算 y

月 da

h(mon

效。

讀入

日期,

日期

元 0 年

,因

串常數","T

常數ril", "D

數陣

old 為

onth

否則若

year

ay 天

nth, y

目前

若是

是否

年至該

因此設

數 hurs

,"Maecem

陣列的

為目前

< 9)

若 ye

年 m

是否

year, i

前日期

是則旗

否為無

該日

設月份

sday

ay",mber

的下標

前日

|| (y

ear 能

month

否為無

isLea

期的 y

旗標 o

無效日

期的

份和

","F

"Jun"};

標,便

期屬

ear =

能被

h 月的

無效日

ap(ye

year

old。

日期。

的總天

星期

Frida

ne",

便可

屬於 1

== 17

4 整

的天數

日期。

ear, o

、mo

。若是

天數:

期的字

ay",

"Ju

可以直

1752

752 &

整除,

數。

。若(

ld)) &

onth

是,則

字串常

"Sat

uly",

直接取

年 9

&& m

,但不

(yea

&&(

、da

則輸

常數

turda

,"Aug

取出表

9 月

mont

不能

ar≥1

(該日

ay,每

出無

ay"}

gust

表述

2 日

th ==

被 1

)&&

日期不

每讀

效日

;

t",

述日

= 9

00

&

讀入

Page 12: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

Chapter 04 應用直接存取類的線性串列程式設計

- 4-7 -

sum= days_of_year(i,old)+ day_of_month(i,year,isLeap(year,old))+daymonth-1i=1

month-1i=1

若該日期在 1752 年 9 月 2 日之後,則為星期 (sum % 7);否則為星期 ((sum+5)% 7),輸出轉換

後的日期,並繼續讀下一個日期。

上述過程一直進行至 year、month 和 day 全為 0 為止。

參考程式

#include <iostream> //預編譯命令 #include <cstdio> #include <cstring> using namespace std; //使用 C++標準程式庫中的所有識別字 const int maxs = 20; //字串常數表的容量 //表示星期幾的字串常數 const char wstr[][maxs] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; //表示月份的字串常數 const char mstr[][maxs] = {"", "January", "February", "March", "April","May", "June", "July", "August", "September", "October", "November", "December"}; bool isLeap(int year, bool old = false) //判斷 year 是否是閏年 { if (old) //year 年 month 月 day 日在 1752 年 9 月 2 日前 return year % 4 == 0 ? true : false; return (year % 100 == 0 ? (year % 400 == 0 ? true : false) : (year % 4 == 0 ? true : false)); } //返回 year 年 month 月的天數 int days_of_month(int month, int year, bool leap) { if (month == 2) return leap ? 29 : 28; int d; switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: d = 31; break; default: d = 30; } return d; } //返回 year 年的天數 int days_of_year(int year, bool old)

Page 13: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

-

4-8

提升程

-

/i

//b

/b

i

程式設

{ r

}

//返回int {

iw

r}

//若//不在bool{

i i i i r

}

//若bool{

r

}

int {

i

c

w

設計的

retur

回 s 在getN

int iwhile

retur

year在 17 val

if (y

if (m

if (d

if (y

retur

year isO

retur

main

int m

cin >

while

的資料

rn i

在 ssNum(

i = e (i ++i

rn i

r≥1 且752 年lid(

year ret

montret

day ret

year ret

rn t

r 年 mOld(

rn y(ye

n(vo

mont

>> m

e (mbooif } e

料結

sLea

s 中的char

0;< t;

< t

且 mon年 9 月int

< 1turn h < turn < 1 turn ==

turn rue;

monthint

ear ear =

id)

h, d

month

monthol ol(!va

co<<

else info

fo

suin

結構力

ap(ye

的位置r s[]

tot &

tot

nth∈月 3 日mont

1) fal0 |fal|| dfal1752fal

;

h 月 dmont

< 17== 1

day,

h >>

h || ld = alidout < " {nt sor (

or (

um +nt w

ear,

,如果], c

&& s

? i

∈{1.日至 1th,

se;| mose;day se;2 &&se;

day 日th,

752 752

yea

day

dayisO(mon<< mis a

um =int sum int sum = daweek

old

果 s 在const

strcm

: -1

.12}3 日的int

onth

> da

& mon

日在 1int

|| && m

ar;

y >>

y || Old(mnth, monthan in

= 0; yy =+= mm =+=

ay;= su

d) ?

在 sst ch

mp(s

1;

且 da的範圍day

> 1

ays_

nth

1752day

(yeamont

yea

yeamontdayh <<nval

= 1;days= 1;days

um %

366

中不ar s

, ss

ay∈{圍內,, in

2)

_of_m

== 9

年 9, in

r ==th ==

r;

r) {th, dy, ye< '/lid d

yy s_of_ mm s_of_

% 7;

6 : 3

不存在ss[]

s[i]

1.. 則返

nt ye

month

9 &&

月 2nt ye

= 175= 9

{ day, ear, ' <<date

< y_yea< m_mon

365;

,則返[max

))

year返回 trear,

h(mo

3 <

日前ear)

52 &&& d

yeaold day." <

year;ar(yymonthnth(m

返回-xs],

r 年 mrue; boo

onth,

<= da

,則返

&& moday <

ar);d)) y << << en

; yy+y, oh; mmmm,

-1 int

mont;否則ol o

, ye

ay &

返回

onth <= 2

//主//主

//讀

//計{//處'/'ndl;//累

++)ld);m++)year

//計

tot

th 月的則返回ld)

ar,

& da

true

< 9);

主函數主函數

讀入日

計算該處理無 <<

累計西

; r, is

計算星

t)

的天數回 fal

isLe

ay <=

e;否

9) |

數 數開始

日期

該日期無效日yea

西元 0

sLea

星期幾

數}且se

eap(

= 13

則返回

|

是否在期r

年至

ap(ye

year

year

)

回 fa

在 17

該日期

ear,

r 年 m

r, o

alse

752 年

期的總

old

mont

ld))

年 9 月

總天數

d));

th 月

)

月 2 日

day 天

日前

Page 14: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

Chapter 04 應用直接存取類的線性串列程式設計

- 4-9 -

if (old) //若該日期在 1752 年 9 月 2 日前 week = (week + 5) % 7; //輸出轉換後的日期和星期幾 cout << mstr[month] << ' ' << day << ", " << year << " is a " << wstr[week] << endl; } cin >> month >> day >> year; //輸入下一個測試組的日期 } return 0; }

Page 15: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

-

4-10

提升程

0 -

4.

程式

電腦

過了

高精

用一

列中

十進

iiscnf

由上

序號

串列

高精

高精

高精

位處

x 和

f

程式設

2

式設

了這

精度

高精度

一個

中。

進位

int int stricin>n=s.for

a

上可

號,

列。

高精度

精度

精度

精度

處理

和 y 按

for a

設計的

設計語

多只

這個範

度數,

度數

個陣列

在具

位數儲

a[10n; ng s>>s; leng(i=0a[i]=

可見,

下標

度數

度數的

度數的

度數

理,高

按如

(i=0a[i]=

的資料

陣列

語言所

只能輸

範圍

有兩

數的表

列表示

具體的

儲存到

00]=

s;

gth(0; i=s[n

高精

標變數

數的基

的基本

的加和

基本

高精度

上的

0; i=a[i

料結

所能表

輸出

,電腦

兩個基

表示

示一個

的實作

到一個

{0};

); <n; -i-1

精度數

數的元

基本

本運算

和減

本的運

度數的

的形式

<(n1]+b[

結構力

表示

16 位

腦就

基本

個高

作中

個陣

i++)1]-'0

數按

元素

本運

算包

運算

的減

式儲存

1>n2 [i];

應用

示和處

位有效

就無法

本問題

高精度

,先

陣列中

)0';

照十

素值對

運算

包括 '+

算是加

減則要

存在

? n

用二

處理的

效的

法正確

題:高

度數

先採用

中。例

////////////

十進位

對應目

+'、'

加和減

要考慮

陣列

n1 :

二:

的整

的十進

確表示

高精度

:將數

用字串

例如

陣列n 用來字串輸入數計算位陣列

位的順

目前位

-'、'

減。和

慮借位

列 a 和

n2)

數和

進位數

示了

度數

數字

串來

,對

a 用來來存放s 用來數字串位長 a 從右

順序

位的

*'、'

和算

位處

和陣列

; i+

高精

和實數

數字

了。在

數的表

字按十

來接收

對於一

來按位放高精來接收串

右向左

序儲存

的十進

'/'。

算術的

處理。

列 b

++){

精度

數的精

,處

在這種

表示和

十進位

收資料

一個高

位存放精度正收資料

左,按

存在整

進位數

的加減

。例如

中,

//

度運

精度

處理 1

種情況

和高精

位分離

料,然

高精

放高精正整數料

按位儲

整數陣

數字

減規則

如,求

n1 為

/進行/逐位

運算

通常

7 位

況下

精度

離,

然後

度正

精度正數的位數

儲存高

陣列

。因

則一

求兩

為 x

行 max位相加

算的

常是有

位有效

下,只

度數的

每位

將字

正整數

正整數數

高精度

列 a 中

此 a

一樣,

兩個非

的位

x{n1加

的實

有限的

效數字

只能透

的基本

位十進

字串中

數,接

,初值

正整數

中,陣

a 是一

程式

非負的

位數,

,n2}

實作

的,

字的正

透過程

本運

進位數

中的各

接收

值全為

陣列下

一種典

式中高

的高

,n2

}位加

作範

如:

正確

程式

算。

數字

各位

與儲

為 0

下標

典型

高精

精度

為 y

加法

在雙

確率為

式設計

字依次

位數字

儲存的

標對應

的直

精度數

度整數

的位

雙精度

為 90%

計來解

次儲存

字轉換

的程式

應高精

直接存

數的加

數 x 和

位數

度方

%。如

解決

存到一

換為對

式段

精度數

存取類

加要考

和 y

,程式

方式下

如果

。對

一個

對應

段如下

數的

類線

考慮

的和

式段

下,

果超

對於

應的

下:

的位

線性

慮進

和。

段如

Page 16: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

Chapter 04 應用直接存取類的線性串列程式設計

- 4-11 -

if ( a[i]>9 ) { //進位處理 a[i]=a[i]-10; a[i+1]++; } }

例如求兩個高精度正整數 x 和 y(x > y) 相減的差,x 和 y 按如上的形式儲存在陣列 a 和陣列

b 中,n 為 x 的位數。若 x < y,則 a 和 b 對換,相減後的差取負。陣列 a 和陣列 b 相減的

程式段如下:

for (i=0; i<n; i++) { if (a[i]>=b[i]) //若對應位夠減,則直接相減,否則借位相減 a[i]=a[i]-b[i]; else { a[i]=a[i]+10-b[i]; an[i+1]--; } }

高精度數的乘和除

下面在高精度數的加和減的基礎上討論高精度數的乘和除。進行高精度數的乘法運算,首

先要確定積的位數。設兩個高精度正整數 a 和 b,LA 為 a 的位數,LB 為 b 的位數。a 和 b

乘積的位數至少為 LA+LB-1,若乘後的第 LA+LB-1 位有進位,則乘積位數為 LA+LB。所

以,高精度正整數 a 和 b 的乘積的位數上限為 LA+LB。

高精度數乘法的演算法思考方式:首先計算被乘數與乘數的每位數字的乘積,其中 a[i] 乘

b[j]的積 累加到陣列 c[i+j] 上,然後對累加結果 c 做一次性進位。

for (i=0; i<=LA-1, i++) //被乘數 a 與乘數 b 的每位數字的乘積累加到積陣列 c 的對應位置上 for (j=0; j<=LB-1; j++) c[i+j] += a[i]*b[j]; for (i=0; i<LA+LB;i++) //累加結果做一次性進位 if(c[i] >= 10) { c[i+1] += c[i]/10; c[i] %= 10; }

求高精度正整數 A÷高精度正整數 B 的商和餘數。演算法思考邏輯如下:

先比較 A 和 B,如果 A<B,則商為 0,餘數為 A;否則基於高精度正整數的減法開始整除,

根據 A 和 B 的位數之差 d1 看 A 夠減 B*10d1 的次數 a1,得到餘數 y1=A- a1*B*10d1;然後計

算 y1 和 B 的位數之差 d2,看 y1 夠減 B*10d2 的次數 a2,得到餘數 y2=y1-a2*B*10d2;⋯;依

此類推,直至得出 yk-1 夠減 B 的次數 ak 為止。 後得到餘數 y= yk-1- ak*B,a1()a2⋯()ak 即為

商(請注意:( ) 表示若 di - di+1 > 1,則 ai+1 前須補 di - di+1 -1 個 0,2≤ i ≤ k-1)。

Page 17: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

-

4-12

4

提升程

2 -

比如

y1=

餘數

有興

.2.

Ma

太喜

悲劇

的意

反向

例如

字元

向數

AC

120

輸入

輸由

輸出

對去

3 244330

試題

線上

程式設

如 A

=1234

數 y2

興趣

1

alidin

喜歡

劇改

意義

向數

如,

元為

數是

CM 需

,結果

0 或

輸入由由空格

對每個去。

樣例輸

4 1 358 705 79

題來源

上測試

設計的

A =1

45-1

2=345

趣的讀

A

nesia

歡演悲

改編為

義,所

數是將

在悲

為零要

是 21)

需要

果不

1200

由 N 個格分開

個測試

輸入:

54 4

源:A

試:P

的資料

2345

2*10

5-2*

讀者不

Add

a 的古

悲劇

為喜劇

所以這

將一個

悲劇中

要被省

)。還

要對反

不是唯

0)。

個測試開的正

試用例

ACM

POJ 15

料結

5,B

03=34

12*1

不妨可

din

古典喜

。但不

劇。顯

這項工

個阿拉

中主角

省略

還要注

反向數

唯一的

為此

試用例正整數

例,輸

Centr

504,

結構力

B=12

45;

101=1

可以

g R

喜劇

不幸

顯然

工作

拉伯

角有

,所

注意反

數進行

的,因

此,本

例組成數組成

輸出一

ral Eu

ZOJ

2,位

345

105;

以試編

Rev

劇演員

幸的是

然,雖

作是很

伯數字

有 124

以,

反向

行計

因為一

本題設

成。輸,這是

行,僅

urope

2001

位數之

與 1

y2 夠

編一下

ver

員(A

是,大

雖然所

很困難

字按相

45 只

如果

向數沒

計算。

一個

設定

入的第是要反

僅包含

1998

1,UV

之 d1

12 的

夠減 1

下高精

rse

Antiq

大多數

所有的

難的

相反的

只草莓

果數字

沒有零

。你的

數可

定沒有

第一行反向相

含一個

8

VA 71

1=3,

的位數

12 的

精度

ed N

que C

數古

的事

的次

莓,現

字結

零結尾

的任

可以是

有 0 因

行僅列相加的

個整數

13

數之差

次數

度除法

Nu

Come

古典戲

事物都

次序寫

現在則

尾有

尾。

務是

是幾個

因為反

列出正的數。

數,將

1234

差 d2

數 a3=

法的程

mb

edian

戲劇是

都改成

寫。把

則有

有零,

是將兩

個數

反向

正整數

將兩個

45 夠

=1,

=8,

程式

ber

ns of

是悲劇

成了它

把第一

有 542

,寫反

兩個反

數的反

向而丟

數 N,然

反向數

樣例輸

34 19981

夠減

345

終得

rs

Mal

劇。

它們

一個數

21 只

反向

反向

反向形

丟失

然後列

數進行

輸出

(12

夠減

得到餘

idine

所以

的反

數字寫

只草莓

數時

數相

形式(

(例

列出測

行求和

2*103

減(1

餘數

esia

以 AC

反面

寫成

莓了

時零會

相加,

(例如

如,

測試用

和,之

3)的

12*1

數 y=1

,AC

CM 的

,但因

成 後

。請注

會被略

,並輸

如 21

設定

用例。

之後再

的次數

01)

05-8

CM)

的戲

因為

後一個

注意

略去

輸出

1 在反

定原來

每個

再反向

數 a

的次

8*12=

喜歡

戲劇指

必須

個數字

意,數

(例

它們

反向

來的

測試用

。在輸

1=1

次數 a

=9 和

歡演喜

指導決

須保持

字,依

數字所

例如,

們的反

前可

數是

用例一

輸出時

,得到

a2=2

和商 1

喜劇

決定將

持劇本

依次類

所有的

120

反向和

可以是

是 12

一行,

時把前

到餘

,得

1028

,而

將一

本原

類推

的前

00 的

和。

是 12

)。

由 2

前導 0

餘數

得到

8。

而不

一些

原有

推。

前置

2,

2 個

0 略

Page 18: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

Chapter 04 應用直接存取類的線性串列程式設計

- 4-13 -

▼解題與分析

設:

Num[0][0] 為被加數的長度,被加數為 Num[0][1..Num[0][0]]。

Num[1][0] 為加數的長度,加數為 Num[1][1..Num[1][0]]。

Num[2][0] 為和的長度,和為 Num[2][1..Num[2][0]]。

首先,分別輸入被加數和加數的數字串,在捨去了尾部的無用 0 後存入 Num[0]和 Num[1],

再 將它們反向儲存。然後,Num[0] 和 Num[1] 相加,得出和陣列 Num[2]。 後反向輸出

Num[2],注意略去尾部的無用 0。

參考程式

#include <iostream> //預編譯命令 #include <cstdio> #include <cstring> #include <string> using namespace std; //使用 C++標準程式庫中的所有識別字 int Num[3][1000]; //Num[0][0]為被加數的長度,被加數為 Num[0][1..Num[0][0]]; //Num[1][0]為加數的長度,加數為 Num[1][1..Num[1][0]];Num[2][0]為和的長度,和為 //Num[2][1..Num[2][0]] void Read(int Ord) //Ord=0,輸入和處理被加數;Ord=1,輸入和處理加數 { int flag=0; string Tmp; cin>>Tmp; //讀數字串 for(int i=Tmp.length()-1;i>=0;i--) //由右而左分析每個數字 { if(Tmp[i] > '0') //捨去尾部的無用 0 後存入高精度陣列 Num[Ord] flag = 1; if(flag) Num[Ord][++Num[Ord][0]] = Tmp[i] - '0'; } for(int i=Num[Ord][0],j=1;i>j;i--,j++) //計算反向數 Num[Ord] { flag = Num[Ord][i]; Num[Ord][i] = Num[Ord][j]; Num[Ord][j] = flag; } } void Add() { Num[2][0] = max(Num[0][0],Num[1][0]); //加數和被加數的 大長度作為相加次數 for(int i=1;i<=Num[2][0];i++) //逐位相加 Num[2][i] = Num[0][i] + Num[1][i]; for(int i=1;i<=Num[2][0];i++) //進位處理 { Num[2][i+1] += Num[2][i]/10; Num[2][i] %= 10;

Page 19: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

-

4-14

4

提升程

4 -

i

有時

用物

.2.2輸入

的 輸出

3 4

試題

線上

程式設

}i if{ }p

}

int {

icf{ }r

}

時候

物件

2 入

分別列

的答案

對於輸

樣例輸

3 4

題來源

上測試

設計的

if(Nu

int ffor(i

print

main

int Ncin>>for(N

retur

候,同

件導向

V

列出 N

案。

輸入每

輸入:

源:T

試:U

的資料

um[2Num

flag int

if( if(

tf("

n()

N; >N; N;N;

memReaReaAdd

rn 0

同類的

向的程

VER

N 和 A

每一行

THE S

UVA 1

料結

][Num[2]= 0i=1;

Numfl

flagpr

\n")

N--)

msetad(0)ad(1)d();

;

的高

程式設

RY

A 的值

行,在

SAMS

10523

結構力

um[2][0] 0; ;i<=N

[2][lag g) rint

;

(Num););

精度

設計

Y EA

值(都

在一行

S, CO

3

][0]++;

Num[

i] >= 1;

f("%

,0,s

度運算

計方法

AS

都是整

中輸出

ONTE

+1]

[2][0

> 0) ;

%d",N

sizeo

算需要

法可使

SY !

數,1

出對應

ST

> 0

0];i

Num[

of(N

要反

使程式

!!!

1 ≤ N

應於 N

)

++)

[2][i

Num))

覆進

式結

N ≤ 15

N 和 A

i]);

);

進行

結構更

50,0

A 的總

(例如

更為清

0 ≤ A∗總和的

如計

清晰

≤ 15∗的整數

樣例輸

1021252

//處

//反

//主//主//輸

//輸

//高//輸//輸//相

計算乘

,運

)。請

值。

輸出

處理

反向輸

主函數主函數輸入測

輸入和

高精度輸入處輸入處相加後

乘冪或

運算更

請列出

高位

輸出和

數 數開始測試用

和處理

度陣列處理和處理和後反向

或多

更為簡

出級數

位的進位

和(去除

始 例數

理每個測

列初始化和被加數和加數

輸出

項式

簡便

除前導

測試用

化為數

式)。

導 0)

用例

0

在這

這種情情況下下,採

Page 20: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

Chapter 04 應用直接存取類的線性串列程式設計

- 4-15 -

▼解題與分析

由級數∑ i*AiNi=1 中項數 N 的上限(150)、底數 A 的上限(15)可以看出,計算乘冪、目前

項及數和非採用高精度運算不可。由於計算過程需要反覆進行高精度的乘法和加法,因此

比較適宜於採用物件導向的程式設計方法。

定義一個名稱為 bigNumber 的類別,其私有部分(private)為一個長度是 len 的高精度陣

列 a,被 bigNumber 類的物件和成員函數存取。其公共介面(public)包括:

bigNumber() 高精度陣列 a 初始化為 0。

int length() 返回高精度陣列 a 的長度。

int at(int k) 返回 a[k]。

void setnum(char s[]) 將字串 s[]轉換成長度為 len 的高精度陣列 a。

bool isZero() 判斷高精度陣列 a 是否為 0。

void add(bigNumber &x) 高精度加法運算:a←a+x。

void multi(bigNumber &x) 高精度乘法運算:a←a*x。

它們是程式可使用的全域函數。

有了以上類別的定義,可使得計算∑ i*AiNi=1 的過程變得十分簡便和清晰:

1) 首先,定義底數 a 和乘冪 ap 為 bigNumber 類別的物件(bigNumber a, ap);將底數字

串 s 轉化為高精度陣列 a(a.setnum(s));乘冪陣列 ap 初始化為 1(ap.setnum("1"));

定義數和 sum 為 bigNumber 類別的物件(bigNumber sum)。

2) 然後迴圈 n 次,每次迴圈計算目前項 i*Ai,並累加入數和 sum:

定義目前項 num 為 bigNumber 類別的物件(bigNumber num)。

num 初始化為 i(sprintf(s, "%d", i; num.setnum(s)))。

計算乘冪 ap←ap*a 和目前項 num←num*ap(ap.multi(a);num.multi(ap))。

累加目前項 sum←sum+num(sum.add(num))。

3) 輸出級數∑ ∗ 的數和 sum.at(sum.length() - 1)⋯sum.at(0)。

Page 21: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

-

4-16

提升程

6 -

##cc c

程式設

參考程

#inc#incconscons

clasp

p

設計的

程式

cludecludest inst in

ss bipriva

publi

的資料

e <ce <cnt mnt m

igNumate: intint

ic: big }

int }

int }

voi }

boo }

voi

}

voi

料結

stdistriaxleaxs

mber

t a[mt len

gNumbmele

t lenre

t atif

re

d selefo

ol isre

d adfo

}inwh

}

le

d muif

結構力

io>ing>en = = 5

r {

maxln;

ber(emseen =

ngthetur

(int f (0

etur

etnumen =or (

sZeretur

dd(bor (

nt khile

en =

ultif (x

500;

en];

) {t(a, 1;

() {rn le

k) <= retu

rn -1

m(ch 0;int a[le

o() rn le

igNuint a[i]a[i a[i]

k = x (a[a[k a[k+

len

(bigx.isZsetn

; ////

////

//

, 0,

{ en;

{ k &urn 1;

har s

i = en++

{ en ==

umberi = ] += + 1] %=

x.len[k]) + 1++]

n > k

gNumbZeronum(

高精度底數字

bigN私有部

公共介

siz

& k a[k]

s[])

str] =

= 1

r &x0; x.a] +=10;

n; {] +=%= 1

k ?

ber ())"0")

度陣列字串

Numb部分

介面

zeof

< le;

{

rlenint

&& a

x) { i < a[i]= a[i;

= a[k10;

len

&x)

;

列 a 的s 的容

er 類:長度

(a))

en)

//將

(s) (s[i

a[0]

x.l; i] /

k] /

: k

{

的容量容量

類別的度為 l

;

將字串

- 1;i] -

==

en;

/ 10;

/ 10;

k;

宣告len 的

串 s[]

; i '0'

0;

i++

;

;

的高精

]轉換

>= 0);

) {

精度陣

//

//

//

換成長

0; i-

//

////

//

//

//

陣列 a

/a 陣

/返回

/返回

長度為

--)

/判斷

/高精/逐位

/處理

/計算

/高精

列初始

回高精

回 a[k

len

斷高精

精度加位相加

理高位

算和的

精度乘

始化為

度陣列

k]

的高精

度陣列

法運算

的進位

實際位

法運算

為 0

列 a 的

精度陣

列 a 是

算:a

位數

算:a←

的長度

陣列 a

是否為

a←a+

←a*x

a

為 0

+x

x

Page 22: 本書 本 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL036300.pdf前言 - v - 本書按照資料結構的知識結構和循序漸進的原則,共分四個Part(基本能力的程式設計實

Chapter 04 應用直接存取類的線性串列程式設計

- 4-17 -

int product[maxlen]; memset(product, 0, sizeof(product)); for (int i = 0; i < len; i++) //被乘數 a 與乘數 x 的每位數字的乘積累加到積陣列 product 的對應位數上 for (int j = 0; j < x.length(); j++) product[i + j] += a[i] * x.at(j); int k = 0; //按照低位至高位的順序,將每一位規範為十進位數字 while (k < len + x.length() - 1) { product[k + 1] += product[k] / 10; product[k++] %= 10; } while (product[k]) { //處理高位端的進位 product[k + 1] += product[k] / 10; product[k++] %= 10; } len = k; //設置乘積數位長度 memcpy(a, product, sizeof(product)); //乘積 product 轉指定給 a } }; int main(void) { int n; //項數 char s[maxs]; //底數字串 while (scanf("%d%s", &n, s) != EOF) { //反覆輸入項數和底數 bigNumber a, ap; //定義底數 a 和乘冪 ap 為 bigNumber 類別的物件 a.setnum(s); //將底數字串轉化為高精度陣列 a ap.setnum("1"); //高精度陣列 ap 初始化為 1 bigNumber sum; //定義數和 sum 為 bigNumber 類別的物件 for (int i = 1; i <= n; i++) { bigNumber num; //定義目前項 num 為 bigNumber 類別的物件 sprintf(s, "%d", i); //將 i 轉化為高精度陣列 num num.setnum(s); ap.multi(a); //計算乘冪 ap←ap*a num.multi(ap); //計算目前項 num←num*ap sum.add(num); //累加目前項 sum←sum+num }

for (int i = sum.length() - 1; i >= 0; i--) //輸出級數 ∑ i*AiNi=1 的數值

printf("%d", sum.at(i)); putchar('\n'); } return 0; }