tft每日頭條

 > 生活

 > 中值定理競賽題目

中值定理競賽題目

生活 更新时间:2024-08-28 13:15:55

昨天晚上兒子說要考考我,讓我做一道題,輸入是一行一句隻有加減運算的算式,譬如1 5-7,讓我寫一個程序來計算出結果。

C 裡沒有原生支持以字符串形式導入一個表達式,并直接計算出結果的能力,可能有一些第三方的庫支持。正常做法,如果表達式裡有加減乘除四則運算,還有小括号來強制指定優先級,則先把表達式轉換成逆波蘭表達式,再計算之。未來我會給出具體解法,難度屬于“普及 /提高-”。

而這一題,隻有加減兩種運算,那就隻能算入門難度了。因為加減運算的優先級相同,都按從左至右的結合律依次兩兩計算。

表達式中有數字,有 和-兩種運算符,混合在了一起,顯然,用string類型來保存整個表達式最方便。

表達式可能會非常長,譬如下面是一個例子:

中值定理競賽題目(NOIP信奧賽算法之加減算式)1

每個數字可能都不止一位,因此,要用一個int類型的變量來逐位提取每個參與運算的數字。

自從2021年9月後,C 14新特性終于可以用于NOIP了,語法糖(syntactic sugar,是指編程語言中可以更容易表達一個操作的語法,它可以使程序員更加容易去使用這門語言,操作可以變得更加清晰、方便,或者更加符合程序員的編程習慣)又有增加,對于一個字符串,可以用以下方式來遍曆字符串s:

中值定理競賽題目(NOIP信奧賽算法之加減算式)2

而在這之前,隻能用下面的語句來遍曆:

中值定理競賽題目(NOIP信奧賽算法之加減算式)3

而且這種用法還會觸發編譯器告警,因為如果i為int類型,i的最大上限值是2,147,483,648,如果字符串的長度超過這個值,多餘的部分就無法遍曆到,正确的寫法如下:

中值定理競賽題目(NOIP信奧賽算法之加減算式)4

這種寫法更為冗長,好在有了C 14,不用再那麼麻煩了。

除了以上三種之外,還有第四種遍曆string的方法,一起來看一下:

中值定理競賽題目(NOIP信奧賽算法之加減算式)5

以上這種是采用疊代器iterator遍曆string的方法。

第一種方法最簡潔,但是也有缺陷,譬如無法從右往左遍曆字符串,也無法在一次循環中同時獲得字符串的多個字符。所以其它幾種方法也并不能被方法一完全取代。在某些場合還是得使用如上這些看起來比較複雜的遍曆方法。

在循環體内,需要對string中的每一個元素做判斷,如果是數字,一種處理方式,否則,就是 或者-,那就是另外一種處理方式。程序結構如下:

中值定理競賽題目(NOIP信奧賽算法之加減算式)6

在處理字符串中的數字之前,首先要搞清一件事, 形如"12345"和12345,在計算機内是完全不同的兩種值,前者是一串字符串,并不能進行數學運算,隻能打印出來。而後者是真實的數字,可進行數學運算。同樣,字符'3'和數字3也完全是兩碼事。在C 裡,字符串用雙引号括起來,字符用單引号括起來。

表達式中夾雜着數字和 和-的運算符。我們隻能把表達式當作一串字符來處理。因此我們要想個辦法,把表達式中的數字字符串,譬如"12345"轉變成12345,好讓它進行數學運算。

我用前面的方案一,把表達式字符串s中的每一個字符依次放入字符變量ch裡。如果ch連續的得到數字字符,則需要把它們合并成一個int類型的整數,方法是用一個初始值為0的變量,不斷的乘以10,再加上這個數字。譬如字符串"123",從左往右,先把1拿出來,放在某個變量num中,然後乘以10再加上2,得到12放入num中,然後把num再乘以10得到120再加上3,就得到了123。

由于ch雖然看上去是數字,其實本質是一個char類型的字符,要通過減去字符'0',得到一個真正的數字。字符0~9在ASCII表中是連續排列的,如果我們得到或者保存一個字符'3',其實它在計算機内真正的值是十進制的51,是該字符的ASCII碼值。顯然我們不能用51去直接運算。那怎麼讓51變成數字3呢?隻要讓它減去'0'的ASCII碼值即可。'0'的ASCII碼值為十進制48, '3' - '0' = 51 - 48 = 3。這就完成了從'3'到3的轉換。

因此對于一連串的數字形式的字符,要轉成int類型的整數,可用如下的方式:

中值定理競賽題目(NOIP信奧賽算法之加減算式)7

接下來,該處理運算符了,如果變量ch遇到一個運算符,該怎麼處理?首先,我們可以意識到,遇到運算符就意味着變量num的數字合并工作暫時告一段落,變量num中的數字可以參于運算了,可以用來和上一次運算的結果進行 或者-的運算。那到底是 還是-呢?這可不是由當前的ch中的運算符來決定的,而是由上一次得到的運算符來決定的。因此,要有一個變量,來保存上一次的運算符。給它取個名字叫last_op吧,給其一個初始值 。并用另一個變量ans來保存上一次運算的結果,給一個初始值0。

試想,當遇到表達式中第一個運算符的時候(無論它是 還是-),num中保存的數字立即就會與初始值為0的ans做 的操作,并把結果保存在ans裡。這就是我們想要的結果。等運算完成,last_op的使命完成,我們就可以把當前ch中保存的運算符,放入last_op中,用于下一次的計算。同時,還要把num置為0,因為num的當前計算已經完成,它要變成0,以迎接下一批連續的數字。代碼可擴展如下:

中值定理競賽題目(NOIP信奧賽算法之加減算式)8

我們快完成了,但這樣的程序還是不太正确,試想一下,所有的表達式是以數字結尾的,并非以 或者-結尾。譬如表達式1 - 3 5, 最後,有一個數字5,最後不可能是一個 或者一個-。 而我們的任意一次計算,都是在遇到運算符 或者-時,才進行的。那最後那個數字,保存在num裡的最後的數字,似乎是沒有機會運行的,因為循環已經結束,它将被悲慘的丢棄掉。解決的辦法也比較巧妙,當我們通過命令行得到整個表達式,在開始做計算之前,我們人為在表達式最後添加一個運算符,随便添加一個 或者-,都可以。這個運算符不會參于運算,隻是為了讓它左側的那個數字,不被丢棄。

整個程序的完整代碼如下:

中值定理競賽題目(NOIP信奧賽算法之加減算式)9

這道題在洛谷上有,編号是P2788,感興趣的同學可以去嘗試一下。

到這裡,這題就做完了。兒子看完後大笑着說,“完全沒有必要那麼麻煩,看我的”,然後他給出了如下的代碼:

中值定理競賽題目(NOIP信奧賽算法之加減算式)10

這段隻有11行的代碼,利用了C 中cin語句的一個特性,當輸入譬如為1 5-3時,如果用一個整數(int)類型的變量通過循環語句連續不斷的去接收它,這個變量會先得到1, 再得到 5, 再得到-3,它會把 号和-号當作該數字的符号位,而不是運算符。如果把得到的這些數字加起來, 就有1 ( 5) (-3)。其實結果與1 5-3并無不同,因此代碼就可以簡單到爆了。

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved