NOTICE

 任何跟文章無關的閒聊,請愛用 留言板(Guestbook)

 想要快速瀏覽主題,請點選單 目錄 標籤。

 停止更新ing,請見諒。 <(_ _)>


2月 04, 2009

【翻譯】Qt Tutorial 2 - Calling it Quits

@
tutorials/tutorial/t2/main.cpp
tutorials/tutorial/t2/t2.pro

  在第一章我們已經建立了一個視窗,現在我們要讓這支程式在使用者使其退出(quit)時正確的退出。



  我們也將使用一個比預設字體更有意思的字體。

 #include <QApplication>
 #include <QFont>
 #include <QPushButton>

 int main(int argc, char *argv[])
 {
     QApplication app(argc, argv);

     QPushButton quit("Quit");
     quit.resize(75, 30);
     quit.setFont(QFont("Times", 18, QFont::Bold));

     QObject::connect(&quit, SIGNAL(clicked()), &app, SLOT(quit()));

     quit.show();
     return app.exec();
 }


Line by Line Walkthrough

 #include <QFont>

  由於這支程式使用了 QFont,所以它需要引入 <QFont>

     QPushButton quit("Quit");

  這時,這個按鈕顯示 Quit,而且這正好就是使用者按下這個按鈕時,程式所需要做的。

     quit.resize(75, 30);

  因為這個按鈕的文字比 "Hello world!" 短一點,所以我們為它選擇了另一個大小。我們也可以使用 QFontMetrics 來設置正確的大小,或是讓 QPushButton 自己挑選合理的預設值。

     quit.setFont(QFont("Times", 18, QFont::Bold));

  這裡我們為這個按鈕選擇了一個新的字體,一個 Times 字型、18 字級的粗體字。你也可以使用 QApplication::setFont() 去改變整個應用程式的預設字體。

     QObject::connect(&quit, SIGNAL(clicked()), &app, SLOT(quit()));

  QObject::connect() 大概是 Qt 主要的特色了。注意 connect()QObject 中的一個靜態(static)函式。別把它跟 Berkeley socket 函式庫中的 connect() 搞混囉。

  這個 connect() 在兩個 Qt 物件(直接或間接繼承自 QObject 的物件)中建立一條單向連接。每個 Qt 物件都擁有 signal (傳遞訊息)與 slots (接收訊息)。由於每個元件都繼承自 QWidget,而 QWidget 又繼承自 QObject,所以所有的元件都是一個 Qt 物件。

  在這裡,quitclicked() signal 被連接到 appquit() slot,所以這個按鈕被按下時,就退出這支程式了。

  Signals and Slots 這份文件詳細的描述了這個主題。


Running the Application

  當你執行這支程式,你會看到一個比第一章更小的視窗,被一個更小的按鈕所填滿。

  請看第一章瞭解如何建立一個 makefile 並建立這個應用程式。


Exercises

  試著改變視窗的大小。按下按鈕去關閉這支程式。

  在 QPushButton 中還有其他 signal 可以讓你連接到 quit 嗎?[提示:QPushButton 繼承了 QAbstractButton 的大部分功能。]


來源:Qt Tutorial 2 - Calling it Quits
版本:4.4.3

【翻譯】Qt Tutorial 1 - Hello World!

@
tutorials/tutorial/t1/main.cpp
tutorials/tutorial/t1/t1.pro

  第一個程式是一個簡易的 "Hello world" 範例。它僅包含了你完成並運作一個 Qt 應用程式的最少需求。下圖是這支程式的螢幕擷圖。



  下面是這支程式的完整原始碼:

 #include <QApplication>
 #include <QPushButton>

 int main(int argc, char *argv[])
 {
     QApplication app(argc, argv);

     QPushButton hello("Hello world!");

     hello.show();
     return app.exec();
 }


Line by Line Walkthrough

 #include <QApplication>

  這一行引入了 QApplication 類別的定義。在每一個使用 Qt 的 GUI 程式中,都必須恰好有一個 QApplication 物件。QApplication 負責管理像是預設字體(font)與游標(cursor)等多種廣泛應用的資源。

 #include <QPushButton>

  這一行引入了 QPushButton 類別的定義。對每個屬於 Qt API 的類別中,都有一個包含其定義的同名標頭(header)檔。

  QPushButton 是一個可以按下(press)或是釋放(release)的 GUI 按鈕。它管理自己的外觀與介面(look and feel),就像其他的 QWidget 一樣。元件(widget)是一個可以處理使用者輸入與繪製圖形的使用者介面物件(user interface object)。程式設計師可以改變所有的介面外觀、許多次要屬性(像是顏色),以及這個元件的內容。一個 QPushButton 可以顯示一段文字或是一個 QIcon

 int main(int argc, char *argv[])
 {

  main() 函式是程式的進入點(entry point)。在使用 Qt 的情況下,main() 幾乎只需要在將控制權轉交給 Qt 函式庫之前,執行一些初始化的動作,Qt 函式庫就會經由事件(event)告知程式使用者的行為。

  argc 這個參數(parameter)是命令列引數(argument)的數量,而 argv 則是這些引數構成的陣列。這是一個標準的 C++ 特色。

     QApplication app(argc, argv);

  物件 app 是這支程式的 QApplication 實現(instance)。它在這裡被建立。我們傳遞 argcargv 到 QApplication 建構子(constructor)中,使其能夠處理某些標準的命令列引數(例如 X11 下的 -display)。所有被 Qt 識別的引數都會從 argv 中移除,argc 也會相應地減少。細節請參看 QApplication::arguments() 文件。

  QApplication 物件必須在任何 GUI 相關的 Qt 元件被使用前建立。

     QPushButton hello("Hello world!");

  在 QApplication 之後,這裡出現了第一個 GUI 相關程式:一個按鈕被建立了。

  這個按鈕被設定成顯示 "Hello world!" 這段文字。因為我們並沒有明確指定一個父視窗(parent window)(QPushButton 建構子的第二個參數),這個按鈕將會自己構成一個擁有外框(frame)與標題列的視窗。

  這個按鈕的大小由預設大小決定。我們可以呼叫(call) QWidget::move() 來指派(assign)元件的一個特定視窗位置,不過這裡我們讓視窗系統決定它的位置。

     hello.show();

  當你建立一個元件時,它是不可見的。你必須呼叫 QWidget::show() 使其變為可見。

     return app.exec();
 }

  這裡就是 main() 將控制權轉交給 Qt 的地方。QCoreApplication::exec() 將會在應用程式結束時返回。(QCoreApplication 是 QApplication 的基礎類別,其構成 QApplication 的核心、非 GUI 的功能,並且可以用來開發非 GUI 的應用程式。)

  在 QCoreApplication::exec() 中,Qt 接收並處理使用者與系統的事件,並將之傳遞到適當的元件中。

  你現在需要編譯並執行這支程式。


Environment Variables

  假如你是在命令列模式下開發 Qt 應用程式,你需要將 Qt 的 bin 資料夾路徑(path)加到環境變數的 PATH 中,確保 Qt 函式庫及執行檔是可以從你的環境中被取得的;這是在針對各種平台的 Installation 教學中所描述的。

  在 Windows 系統上,若是你使用開始功能表 > 所有程式 > Qt 選單中的 Command Prompt 來取得命令列工具,它會自動為你完成設置。若是你使用開始功能表 > 執行 > Command 來取得命令列工具,你就必須要自己設置 PATH 變數。


Building an application

  這個指導範例位於 Qt 的 examples/tutorials/tutorial 資料夾。假如你直接安裝 Qt 的二元檔套裝軟體(package),預先建立的這些範例也會被安裝。若你是自行創建 Qt,這些範例也會同時被建立。無論如何,你都需要自己修改或是建立範例以學習使用 Qt。

  假設你已經複製了範例的 .cpp.h 檔到另一個空資料夾中,你需要在這裡做一些改變,下一步是在這個資料夾中建立一個 Qt makefile。要建立一個 Qt makefile,需要使用 Qt 提供的 qmake 建構工具。在包含你原始碼的目錄下,執行下面兩條指令以建立 makefile:

 qmake -project
 qmake

  第一條指令告知 qmake 創建一個 project(.pro) 檔。第二條指令告知 qmake 根據 .pro 檔去創建一個特定平臺的 makefile。

  現在你可以執行 make(或是 nmake,假如你使用的是 Visual Studio),然後執行你的第一個 Qt 應用程式了!


Running this example

  當你執行這個範例,你將會看到一個顯示單一按鈕的小視窗,在按紐上,你可以讀到著名的那句:"Hello world!"。


Exercises

  試著去調整視窗大小。按下按鈕。若你是在 X11 下執行,試著去執行 -geometry 選項(舉例來說,-geometry 100x200+10+20)。


來源:Qt Tutorial 1 - Hello World!
版本:4.4.3

【翻譯】Qt Tutorial

@
  這份指導教學提供了一份使用 Qt toolkit 撰寫 GUI 程式的介紹。它並沒有包含所有的東西;其將重點放在傳授撰寫 GUI 程式的設計哲學,以及一些需要被介紹的 Qt 特色。一些較為一般的特色將不會在這份教學中被提及。

  章節一從一個最小的 "Hello world" 程式開始,並於接下來的每一章介紹新的概念。直到章節十四,章節一的 "Hello world" 程式將會變成一個 650 行的遊戲。

  假如 Qt 對你而言完全是陌生的,且未讀過 How to Learn Qt 的話,請先讀過一次。

  這份指導教學的原始碼都放在 Qt 的 examples/tutorials/tutorial 資料夾中。


指導章節:
1. Hello World!
2. Calling it Quits
3. Family Values
4. Let There Be Widgets
5. Building Blocks
6. Building Blocks Galore!
7. One Thing Leads to Another
8. Preparing for Battle
9. With Cannon You Can
10. Smooth as Silk
11. Giving It a Shot
12. Hanging in the Air the Way Bricks Don't
13. Game Over
14. Facing the Wall


  這個小遊戲看起來並沒有那麼像一個時髦的 GUI 應用程式。雖然它使用了一些 GUI 技術,不過在你開始使用它之後,我們建議你試試這個 Application 範例,它提供了一個擁有選單、工具列、一個狀態列等等的小型 GUI 應用程式。


來源:Qt Tutorial
版本:4.4.3

1月 30, 2009

【介紹】USACO - How To Start

@
  延續前一篇的介紹,現在讓我們看看要如何申請一組 USACO Trainng 的帳號,並開始我們的解題之路!



  首先,來到 USACO Trainng 的首頁,點選 "Register here for a username/password" 開始註冊。


  接著就依照欄位,把資料填完就可以了。

  選填欄位可以先全部不填,等收到認證信登入之後,網站會再要求你把需要的選填資料填完。


  註冊成功之後,應該會看到如上圖的畫面。

  接著到註冊用的電子郵件信箱收信之後,應該會收到一封主旨為 "USACO Training Registration Info with Password" 的信。內文如下:

Here is the information you need to participate in the USACO Training Program:

* Use http://ace.delos.com/usacogate as the gateway URL.

* Your permanent personalized username and password are:
  Name: (你的名字)
  UserName: (你的帳號)
  Password: (你的密碼)

Please save this UserName and Password as they are permanently assigned to you.

Rob Kolstad, Head Coach

USA Computing Olympiad * kolstad@ace.delos.com * 877-753-3567


  然後回到首頁,用剛剛信上寫著的帳號密碼登入。


  如果剛剛沒有填國家的話,應該會顯示上圖的畫面。

  找到自己的國家名稱,點下去就對了。


  如果剛剛沒有填中學畢業年的話,應該會顯示上圖的畫面。

  基本上,網頁上面有說:假如不想洩漏(我是懶得查XD)畢業年的話,直接填入 "9999" 即可。


  接著就能進入上圖的畫面了。

  不過記得,由於密碼是網站給你的,為了避免忘記密碼,請記得點選上方的 "Change Password" 修改密碼。


  假如點選了 "Change Password",照著填上去按下 "Submit" 送出就好了。


  回到剛才的頁面。

  一開始還不能開始寫題目,我們需要先點選 "TEXT Introduction",看官方的介紹文章。


  大致上是介紹 USACO 跟這個網站的內容。有興趣的人可以仔細看看。


  回到剛才的頁面,發現 Section 1.1 的文字變成連結了。

  接著請點選 "TEXT Submitting Solutions",裡面會告訴你 USACO Trainng 上傳程式的方式與程式格式。

  簡單來說,就是上傳的程式裡,前幾行必須用註解標記一些相關資訊。以 C++ 為例,你需要在開頭加入:

/*
ID: (你的帳號)
PROG: (題目名稱)
LANG: C++
*/

  並記得在 main() 主函式中加入 "return 0;"。

  基本上裡面寫得很仔細,一定要先仔細讀過。


  接著來實際演練一遍。

  在文章裡把它的範例程式複製下來(記得將 ID 修改成自己的),上傳程式原始碼就可以了。


  接著會顯示上傳後的結果。

  假如結果有錯,網頁會列出你錯誤的那筆測試資料與正確答案,以方便除錯。

  假如都沒有錯誤,網頁就會列出所有測試資料,與你的程式跑每筆測試資料所花的時間。


  終於,我們可以來正式挑戰 USACO Trainng 的題目了。



  題目內文裡面,會標示程式名稱、輸入檔名稱與輸出檔名稱,記得不要搞錯了。


  當解出題目之後,題目連結後面會出現一個 [ANALYSIS] 的連結。


  點進去之後,就是官方的題目分析,與參考的程式碼了。


  當解完所有 Section 1.1 的題目後,才可以開始寫 Section 1.2,所以寫題目只能照著章節跑。

  只要能解完 Section 1 到 Section 6 的題目,你就成功闖關 USACO Trainng 了!祝各位好運。

1月 29, 2009

【解題】錄製專輯 - Record

@
台北市96學年度高中資訊學科能力競賽 - 錄製專輯 (Record)


問題描述

  Jolin是個愛唱歌的小孩,每次總喜歡邊唱邊用電腦把自己的歌聲錄下來,因此長久下來,在她的電腦裡,已儲存了為數不小的個人歌唱作品。由於耶誕節快要到了,為了準備一份特別的耶誕禮物給爸爸,Jolin準備從電腦中儲存的個人歌唱作品,挑選幾首歌製成一張個人專輯CD。由於每張CD的容量有限,而Jolin的個人歌唱作品早已遠遠超過一張CD可收錄的容量,因此Jolin希望你可以幫她想辦法,讓她所製作的專輯中,能有數目最多的歌曲(請注意:每一首歌只能被收錄一次),同時必需剛好裝滿整張CD,不留下任何未使用的空間。


輸入檔格式(C:\record\input.txt)

  輸入檔中的第一行為一個正整數N,代表Jolin的個人歌唱作品數目。第二行則有N個以空白相間隔的正整數Xi,分別代表第i首個人歌唱作品的大小(單位為MBytes)。第三行則有一個正整數S,代表CD的容量(單位為MBytes)。

  為簡化計算過程起見,我們假設每一首歌唱作品的大小皆不相同,同時N≦100,Xi≦200,S≦10000。


輸出檔格式 (C:\record\output.txt)

  請根據輸入檔的資料,在輸出檔中依序印出兩個正整數L與K。其中,L代表最多可以在CD中收錄的歌曲數目,K代表共有幾種方式可以收錄L首歌曲於CD中。注意,若歌曲曲目相同,但排列順序不同,仍視為不同的收錄方式。

  若沒有任何方法可以錄滿整片CD,則L=K=0。


輸入檔範例1

5
10 50 30 70 60
80


輸出檔範例1

2 4


輸入檔範例2

5
10 50 30 70 60
20


輸出檔範例2

0 0


解題思考

  對於這一題,我們首先需要得知,哪些歌加起來可以剛好裝滿整張CD。接著,由於歌曲順序不同仍視為不同的收錄法,因此假設n首歌剛好可以裝滿整張CD,就會有n!種收錄方式。

  所以,現在的問題就在於:該如何得知,哪幾首歌剛好可以裝滿整張CD呢?根據建議,這裡提供一張圖做參考:



  我的作法是,以迴圈搭配遞迴的方式選歌。假設現在取到第一首歌,容量是30。接著,再藉由遞迴的方式選第二首歌。由於第二首歌的大小為60,兩首歌的總容量超過CD大小,因此第二首歌並不能列入CD當中。以此類推,直到抓到最後一首歌,或是CD容量已滿為止。

  或許你會注意到,除了CD剩餘容量外,參考圖片中還有一個"歌曲剩餘"的大小。這個數值代表的意義是:還沒被判斷是否可以放入CD的歌曲總容量(即圖片中未圈選及劃叉的歌曲)。

  記錄這個數字做什麼呢?因為只要這個數字小於CD的剩餘容量,就算這些歌全都收錄在CD中,也不會到題目要求的"剛好裝滿"CD。因此,只要歌曲剩餘大小小於CD剩餘大小,就代表目前的選擇並不可行。

  只要掌握這些概念,程式應該就能夠輕易的實現了。


  結果答案完全是錯的。


  這一題用這種方式來作,若是測試資料的 n 過大,將會導致執行結果超時。因此,勢必要使用別的方式來解才行。 (感謝網友 大丁丁 指正)

  其實,這樣的題型就是所謂的背包問題(knapsack problem)。若是要解出這種題型,比較高效率的方法是利用動態規劃(dynamic programming)

  首先,先要得出一套「公式」,來求得只在前 i 首歌中做選擇,且恰好能裝滿容量為 v 的專輯的最大歌曲數。我們將之設為 f(i, v)。其中,若是我們選了第 i 首歌,則 f(i, v) 將可以看作 f(i - 1, v - x[i]) + 1。也就是「只在前 i - 1 首歌中做選擇,且恰好能裝滿容量為 v - x[i] (因為 x[i] 的空間被第 i 首歌佔據了)的專輯的最大歌曲數加一(第 i 首歌本身)」。

  而若是我們不選第 i 首歌,則 f(i, v) 將可以看作 f(i - 1, v)。也就是「只在前 i - 1 首歌中做選擇,且恰好能裝滿容量為 v (因為不選第 i 首歌)的專輯的最大歌曲數」。如此,便可以得出 f(i, v) = maximum(f(i - 1, v - x[i]) + 1, f(i - 1, v))

  再加上定義出 f(0, 0) = 0 (因為 0 首歌裝滿容量為 0 的專輯能裝的最大歌曲數也為 0 首),且 f(0, v) = -∞ (選 0 首歌裝滿容量大於 0 的專輯的情況必不可能出現),再搭配迴圈就能得到正確的結果了。


  那麼,要如何在不考慮順序情況下,得出的最大歌曲組合數量呢?

  同樣的,若我們設 g(i, v) 為「只在前 i 首歌中做選擇,且恰好能裝滿容量為 v 的專輯的最大歌曲組合數」,再循著類似的原理累加,便可以得出結果。最後,以 g(i, v) 作為係數,乘以 f(i, v) 階層,就是包含各種不同順序的最大歌曲組合數量了。


  還有要注意的一點是,計算出來的結果數字會相當大(畢竟牽扯到階層),所以要用大數來存。這邊允許我偷個懶,直接用我以前寫的大數類別吧。


  其實,這題我還很蠢的把題目的「最大裝滿專輯的歌曲組合數量」,誤解成「能裝滿專輯的歌曲組合數量」,大大的把題目給複雜化了。結果我好不容易寫出來之後,才發現跟大丁丁那弄來的 AC code 跑出的結果有那麼「一點點」不一樣。經過如此改正之後,這題我才算真正解出來。


參考解答(C++)

#include <iostream>
#include <fstream>

#include "include/Large.h"

using namespace std;

int main(void)
{
    ifstream in("C:/record/input.txt");
    ofstream out("C:/record/output.txt", ios_base::trunc);

    cout << "讀入資料 . . ." << endl;

    int n;
    in >> n;
    cout << n << endl;

    int *x = new int[n];
    for (int i = 0; i < n; i++)
    {
        in >> x[i];
        cout << x[i] << " ";
    }

    int s;
    in >> s;
    cout << endl << s << endl;

    in.close();

    int *dp = new int[s + 1];
    dp[0] = 0;
    memset(dp + 1, 0xFF, sizeof(int) * s);

    large *g = new large[s + 1];
    g[0] = 1;

    // dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + 1)
    for (int i = 0; i < n; i++)
    {
        for (int j = s; j >= x[i]; j--)
        {
            if (dp[j - x[i]] >= 0)
            {
                // 找到比當前最多歌曲組合更多歌曲的組合
                if (dp[j - x[i]] + 1 > dp[j])
                {
                    dp[j] = dp[j - x[i]] + 1;
                    g[j] = g[j - x[i]];
                }
                else if (dp[j - x[i]] + 1 == dp[j])
                {
                    // 累加最多歌曲組合的數量
                    g[j] += g[j - x[i]];
                }
            }
        }
    }

    // 計算順序不同的組合
    large number = g[s];
    for (int i = 2; i <= dp[s]; i++)
    {
        number *= i;
    }

    if (dp[s] < 0) { dp[s] = 0; }

    // 輸出得到的結果
    out << dp[s] << " " << number << endl;
    out.close();

    cout << endl << dp[s] << " " << number << endl;
    cout << "輸出資料在 ouput.txt" << endl;

    delete [] x;
    delete [] dp;
    delete [] g;

    system("pause");
}

【介紹】USACO - What's This

@
  USACO (United States of America Computing Olympiad,美國資訊奧林匹亞)是美國為其中學生所舉辦的程式設計競賽,能使用的程式語言包含 CC++Java 以及 Pascal

  USACO 舉辦的目的在於訓練美國中學生的邏輯思考與解決問題的能力,並從中選拔出每年 IOI (International Olympiad in Informatics,奧林匹亞資訊學科) 的參賽選手。而為了確實培訓將來要參加 IOI 的國手,USACO 特別建立了所謂的 USACO Training




  USACO Training 是一個線上的網路題庫,主要是用來訓練程式設計、活用演算法與資料結構的能力。題目的內容五花八門,涵蓋了各式各樣的問題。且 USACO Training 題目依照難易度,由簡到難共分為 6 個章節,必須以章節順序依次將題目完成。

  除了循序漸進之外,USACO Training 還提供了許多程式設計相關的教學文章,像是貪婪演算法(Greedy Algorithm)深度優先搜尋(Depth-First Search,DFS)廣度優先搜尋(Breadth-First search,BFS)動態規劃(Dynamic Programming,DP)等等。

  看完教學文章之後,再利用題庫中的題目做練習,學習的效果相當顯著。若是程式有錯誤,網站還會列出程式的錯誤訊息、或是錯誤的那筆測試資料與正確答案的對照,以便於除錯。而在解出題目之後,USACO Training 還有詳細的題目分析講解與參考程式。

  貼心的是,遇上某些太難的題目,USACO Training 還會提供一些小提示。只要順著提示的引導,往往就可以寫出那一題的答案了。


  總而言之,我覺得 USACO Training 的題目其實還滿有意思的。在一邊寫的同時,感覺也學到了不少東西。所以新年新希望,就是能夠將 USACO Training 中的題目全部寫完囉(笑)。


  以下是一些相關網站及參考資料,有興趣的人可以參閱:

USA Computing Olympiad
USACO Training Program Gateway
USACO Contest Gateway
United States of America Computing Olympiad - Wikipedia

1月 20, 2009

【解題】Is This Integration?

@
ACM Volume CII 10209 - Is This Integration?


The Problem

In the image below you can see a square ABCD, where AB = BC = CD = DA = a. Four arcs are drawn taking the four vertexes A, B, C, D as centers and a as the radius. The arc that is drawn taking A as center, starts at neighboring vertex B and ends at neighboring vertex D. All other arcs are drawn in a similar fashion. Regions of three different shapes are created in this fashion. You will have to determine the total area if these different shaped regions.




Input

The input file contains a floating-point number a (0 <= a <= 10000) in each line which indicates the length of one side of the square. Input is terminated by end of file.


Output

For each line of input, output in a single line the total area of the three types of region (filled with different patterns in the image above). These three numbers will of course be floating point numbers with three digits after the decimal point. First number will denote the area of the striped region, the second number will denote the total area of the dotted regions and the third number will denote the area of the rest of the regions.


Sample Input

0.1
0.2
0.3


Sample Output

0.003 0.005 0.002
0.013 0.020 0.007
0.028 0.046 0.016


解題思考

  這題是數學題,求出公式這題就搞定了。雖然如此,這題我還是想了好久。

  其實,只要能畫出那條關鍵的輔助線,這題並沒有那麼難:



  看出來了嗎?


  為了方便起見,我們將黃色區域面積設為 A,綠色區域面積設為 B,藍色區域面積設為 C。

  由於圖中的 BF 線段(即圓半徑)長度為 a,BE 線段長度為 a / 2,我們便可得到:∠BFE = ∠CBF = 30°。於是,我們就可以求出,圖中八分之一的藍色區域面積為:a × (a / 2) - [(a / 2) × (√3 a / 2)] / 2 - a × a × π / 12。

  經過整理,便可得到:C = a × a × [4 - √3 - (2π / 3)]


  接著,由於整個圖形面積為 A + B + C = a × a,又因為圖中的四分之一圓面積為 A + 3B / 4 + C / 2 = a × a × π / 4。經過聯立消去法之後得到:B + 2C = a × a × (4 - π)。

  將 C 帶入上述算式中,便可得到:B = a × a × [-4 - 2√3 + (π / 3)]


  同樣的,把 B 與 C 代入 A + B + C = a × a 中,也可以得出:A = a × a × [1 + (π / 3) - √3]


參考解答(C++)

#include <iostream>
#include <iomanip>
#include <cmath>

#define PI 2.0 * acos(0.0)
#define A(r) (r) * (r) * (1  + PI * 1.0 / 3.0 - sqrt(3))
#define B(r) (r) * (r) * (-4 + PI * 1.0 / 3.0 + sqrt(3) * 2)
#define C(r) (r) * (r) * (4  - PI * 2.0 / 3.0 - sqrt(3))

using namespace std;

int main(void)
{
    double a;

    // 設定顯示至小數點第三位
    cout << setiosflags(ios::fixed) << setprecision(3);

    while (cin >> a)
    {
        cout << A(a) << " " << B(a) << " " << C(a) << endl;
    }

#ifndef ONLINE_JUDGE
    system("pause");
#endif
}