OVa Online Judge 學習筆記- AOAPC I: Volume 2. Data Structure Lists

一、題目

二、C++ STL Container

原因:避免自己構造相應的list,包括靜態存儲結構,鏈式存儲結構。

1.數組 array:<array>

Arrays are fixed-size sequence containers: they hold a specific number of elements ordered in a strict linear sequence.

優點:快速訪問存取。

Container properties:

Sequence

Contiguous storage

Fixed-size aggregate

2.向量 vector && vector<bool>:<vector>

Vectors are sequence containers representing arrays that can change in size.

優點:快速訪問存取。

Container properties:

Sequence

Dynamic array

Allocator-aware

3.雙向鏈表 list:<list>

Lists are sequence containers that allow constant time insert and erase operations anywhere within the sequence, and iteration in both directions.

優點:快速插入刪除操作。

Container properties:

Sequence

Doubly-linked list

Allocator-aware

4.前向鏈表 forward_list:<forward_list>

Forward lists are sequence containers that allow constant time insert and erase operations anywhere within the sequence.

優點:快速插入刪除操作。

Container properties:

Sequence

linked list

Allocator-aware

5.堆棧 stack:<stack>

Stacks are a type of container adaptor, specifically designed to operate in a LIFO context (last-in first-out), where elements are inserted and extracted only from one end of the container.

  • empty
  • size
  • back
  • push_back
  • pop_back

特點:LIFO。

6.隊列 <queue>

1)queue

queues are a type of container adaptor, specifically designed to operate in a FIFO context (first-in first-out), where elements are inserted into one end of the container and extracted from the other.

  • empty
  • size
  • front
  • back
  • push_back
  • pop_front

特點:FIFO。

2) 優先隊列:priority_queue

Priority queues are a type of container adaptors, specifically designed such that its first element is always the greatest of the elements it contains, according to some strict weak ordering criterion.

This context is similar to a heap, where elements can be inserted at any moment, and only themax heap element can be retrieved (the one at the top in thepriority queue).

特點:heap。

  • empty()
  • size()
  • front()
  • push_back()
  • pop_back()

7.雙端隊列 <deque>

deque (usually pronounced like "deck") is an irregular acronym of double-ended queue. Double-ended queues are sequence containers with dynamic sizes that can be expanded or contracted on both ends (either its front or its back).

Container properties:

Sequence

Dynamic array

Allocator-aware

三、做題筆記

1.127 - "Accordian" Patience

知識點:

1.撲克的堆疊操作只能是最上方,就像堆棧一樣,因此可以用stack<string>數據結構。

2.撲克的序列相當於上述各個堆棧形成的線性表,涉及到元素的訪問及刪除兩種操作,可以用vector<stack<string>>數據結構。

注意:

1.warning:

warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

原因循環裏面和size()比較時出現,因爲size返回值是unsigned integer型,而循環計數一般採用int型,改爲size_t型可以解除該warning:

for (size_t i = 0; i < cards.size(); i++) {

2.error:

error: ‘>>’ should be ‘> >’ within a nested template argument list
vector<stack<string>> cards;

採用g++ -std=c++11 新標準時並不會報錯,舊標準會出錯。

3.對問題理解:

程序一直沒跑出例子的結果,後面通過各種可能性測試發現是以下語義理解錯誤:

Whenever the card matches its immediate neighbour on the left, or matches the third card to the left, it may be moved onto that card. 

開始採用的方法,是優先移動到immediate neighbour on the left,程序結果出錯。

後面改爲優先移動到 the third card to the left,程序結果正確。

這裏可以發現問題中“it"單詞是加粗的,以後可以慎重考慮這些加粗的單詞並正確理解題意,按照上面那句話意思,仔細思考,確實存在優先移動到第三張card的含義。

4.STL container

有些方法,是C++11標準纔有的,使用需加入std=c++11編譯選項,這部分可以通過C++ reference網站進行參考,網站在講解時會有這些提示。

5.測試工具:

可以自己生成測試input.txt文件,輸出後與http://uvatoolkit.com/problemssolve.php 輸入該input.txt文件後進行比對,看結果對不對。

這個適用於一些特殊的數據,需要參考輸出時或UVAOJ網站連接不順暢時使用。

做題記錄:TL -> AC

1.Time limit exceeded

處理:由於字符串最多隻有兩個,string 改用 char[3],開闢一個全局變量char a[52][3]存儲所有數據,並且stack只存儲指向正確位置的指針。

修改這部分後獲得AC。

代碼:

/**
 * @file id_127.cpp
 * @brief AOAPC I 127
 * @author chenxilinsidney
 * @version 1.0
 * @date 2015-03-27
 */

#include <iostream>
#include <string>
#include <vector>
#include <stack>

using namespace std;

bool pile(const char* a, const char* b)
{
    return (a[0] == b[0] || a[1] == b[1]);
}

char single_card[52][3];

int main()
{
    vector< stack<char*> > cards;
    int single_card_index = 0;
    while (cin >> single_card[single_card_index] &&
            single_card[single_card_index][0] != '#') {
        // add pile to card
        stack<char*> single_pile;
        single_pile.push(single_card[single_card_index]);
        cards.push_back(single_pile);
        single_card_index++;
        // proccess a group until spectial count
        if (cards.size() != 52)
            continue;
        int finish_flag = 1;
        int remain = cards.size();
        while (finish_flag) {
            finish_flag = 0;
            for (int i = 0; i < remain; i++) {
                int pile_flag = 1;
                while (pile_flag) {
                    pile_flag = 0;
                    if (i > 2 && pile(cards[i].top(), cards[i - 3].top())) {
                        cards[i - 3].push(cards[i].top());
                        cards[i].pop();
                        if (cards[i].empty()) {
                            cards.erase(cards.begin() + i);
                            remain--;
                        }
                        i -= 3;
                        pile_flag = 1;
                        finish_flag = 1;
                        continue;
                    }
                    if (i > 0 && pile(cards[i].top(), cards[i - 1].top())) {
                        cards[i - 1].push(cards[i].top());
                        cards[i].pop();
                        if (cards[i].empty()) {
                            cards.erase(cards.begin() + i);
                            remain--;
                        }
                        i--;
                        pile_flag = 1;
                        finish_flag = 1;
                        continue;
                    }
                }
            }
        }
        if (remain != 1)
            cout << remain << " piles remaining:";
        else
            cout << remain << " pile remaining:";
        for (size_t i = 0; i < cards.size(); i++) {
            cout << " " << cards[i].size(); 
        }
        cout << endl;
        // clear data
        single_card_index = 0;
        cards.clear();
    }
    return 0;
}

2.101 - The Blocks Problem

知識點:

C++:

1.第一種方法:建立一個標記block的結構體數組,記錄每個block所在的block position位置以及block在該位置的排名。

這樣,查詢每個block的狀態時間複雜度爲O(n)。再根據操作要求進行操作。麻煩的地方在於處理pile命令時,取出該pile後還得根據不同block在排位值排名進行排序以保證次序不變,這裏使用map快速解決。

2.第二種方法:建立一個記錄block position狀態的vector< vector<int> >結構,每個position又由vector<int>維護該位置所有block的排名及標號。

這樣,查詢每個block的狀態時間複雜度爲O(n^2)。但是插入刪除操作很快,因爲他們總是有序的,處理pile時可以用queue快速處理。

做題記錄:WA -> AC

1.正確理解題目含義!!!如果不肯定可以利用uvatookit測試!!!!!!!看清題目每一句話的意思,不要忽略重要信息並自己假定邏輯。

這裏理解題目出錯導致結果錯誤,雖然例子結果恰好一致,但是利用uvatookit很容易發現別的輸入下就出錯了。

代碼:

/**
 * @file id_101.cpp
 * @brief AOAPC I 101
 * @author chenxilinsidney
 * @version 1.0
 * @date 2015-03-27
 */

#include <iostream>
#include <string>
#include <vector>
#include <queue>

using namespace std;

vector< vector<int> > blocks;

int main()
{
    // get block numbers < 25
    int num_blocks;
    cin >> num_blocks;
    cin.get();
    for (int i = 0; i < num_blocks; i++) {
        vector<int> block;
        block.push_back(i);
        blocks.push_back(block);
    }
    string command;
    int value_a;
    int value_b;
    string position;
    while (cin >> command && command != "quit") {
        cin >> value_a >> position >> value_b;
#ifndef ONLINE_JUDGE
        cout << command << value_a << position << value_b << endl;
#endif
        cin.get();
        queue<int> data;
        // ignore illegal command
        if (value_a == value_b) continue;
        int blocks_a, blocks_b;
        int block_a, block_b;
        for (size_t i = 0; i < blocks.size(); i++) {
            for (size_t j = 0; j < blocks[i].size(); j++) {
                if (blocks[i][j] == value_a) {
                    blocks_a = i;
                    block_a = j;
                }
                if (blocks[i][j] == value_b) {
                    blocks_b = i;
                    block_b = j;
                }
            }
        }
        if (blocks_a == blocks_b) continue;
        // move and pile
        if (command == "move") {
            // move a only
            data.push(value_a);
            // return any blocks that are stacked on top of a to their
            // initial position
            for (size_t k = block_a + 1; k < blocks[blocks_a].size(); k++) {
                int i = blocks[blocks_a][k];
                blocks[i].push_back(i);
            }
        } else {
            // pile a
            for (size_t k = block_a; k < blocks[blocks_a].size(); k++)
                data.push(blocks[blocks_a][k]);
        }
        // remove old data of a
        blocks[blocks_a].erase(blocks[blocks_a].begin() + block_a,
                blocks[blocks_a].end());
#ifndef ONLINE_JUDGE
        cout << "data:" << data.size() << endl;
#endif
        // onto and over
        if (position == "over") {
            // onto the top of stack containing block b
            while (!data.empty()) {
                blocks[blocks_b].push_back(data.front());
                data.pop();
            }
        } else {
            // return any blocks that are stacked on top of b to their
            // initial position
            for (size_t k = block_b + 1; k < blocks[blocks_b].size(); k++) {
                int i = blocks[blocks_b][k];
                blocks[i].push_back(i);
            }
            // clear
            blocks[blocks_b].erase(blocks[blocks_b].begin() + block_b + 1,
                    blocks[blocks_b].end());
        }
        // refresh new data of a
        while (!data.empty()) {
            blocks[blocks_b].insert(blocks[blocks_b].begin() + block_b + 1,
                    data.front()); 
            data.pop();
        }
    }
    // output result
    for (size_t i = 0; i < blocks.size(); i++) {
        cout << i << ":";
        for (size_t j = 0; j < blocks[i].size(); j++) {
            cout << " " << blocks[i][j];
        }
        cout << endl;
    }
    return 0;
}

3.133 - The Dole Queue MARK

雙向約瑟夫環

知識點:循環鏈表的索引定位以及鏈表插入刪除操作。

技巧:

1.循環circlr的索引加入偏移量求新索引,單用求餘可能會錯,因爲偏移可能大於一圈,導致求餘時仍然爲負值。

優化前出錯: k_index = (k_index + N) % N;

優化後正確輸出:

while (k_index < 0) k_index += N;
while (k_index > N) k_index -= N;

2.閉環時索引要考慮爲零的情況(假設索引值1-N)

while (k_index < 0) k_index += N;
while (k_index > N) k_index -= N;
while (m_index < 0) m_index += N;
while (m_index > N) m_index -= N;
if (k_index == 0) k_index = N;
if (m_index == 0) m_index = N;

3.索引時確定以下標爲1開始索引還是0開始索引,不要弄混了。

4.刪除多個結點時需要考慮先刪除的結點對後刪除的結點的影響!!!!這裏有刪除先後順序問題,如果索引值都不變情況下同時刪除,應該先刪除靠後的結點,在刪除靠前的結點。

C++:

1.使用vector操作數據,原因:方便索引及刪除操作。

2.cout 輸出流格式化:(與printf對比學習) 頭文件 <iomanip>

這裏解決問題時使用到的:setw(3)(->%3d) 代碼:cout << setw(3) << first_remove;

拓展:輸出格式控制

(參考:http://c.biancheng.net/cpp/biancheng/view/116.htmlhttp://c.biancheng.net/cpp/biancheng/view/2227.html

對輸出格式的控制,既可以用控制符,也可以用cout流的有關成員函數,二者的作用是相同的。

1.使用控制符控制輸出格式:

輸入輸出流的控制符
控制符 作 用
dec 設置數值的基數爲10
hex 設置數值的基數爲16
oct 設置數值的基數爲8
setfill(c) 設置填充字符c,c可以是字符常量或字符變量
setprecision(n) 設置浮點數的精度爲n位。在以一般十進制小數形式輸出時,n代表有效數字。在以fixed(固定小數位數)形式和 scientific(指數)形式輸出時,n爲小數位數
setw(n) 設置字段寬度爲n位
setiosflags( ios::fixed) 設置浮點數以固定的小數位數顯示
setiosftags( ios::scientific) 設置浮點數以科學記數法(即指數形式)顯示
setiosflags( ios::left) 輸出數據左對齊
setiosflags( ios::right) 輸出數據右對齊
setiosflags( ios::skipws) 忽略前導的空格
setiosflags( ios::uppercase) 數據以十六進制形式輸出時字母以大寫表示
setiosflags( ios::lowercase) 數據以十六進制形式輸出時宇母以小寫表示
setiosflags(ios::showpos) 輸出正數時給出“+”號

需要注意的是: 如果使用了控制符,在程序單位的開頭除了要加iostream頭文件外,還要加iomanip頭文件。

例子:

cout<<setprecision(3)<<setiosflags(ios::fixed)<<3.1415926<<endl;

2.用流對象的成員函數控制輸出格式


用於控輸出格式的流成員函數
流成員函數 與之作用相同的控制符 作用
precision(n) setprecision(n) 設置實數的精度爲n位
width(n) setw(n) 設置字段寬度爲n位
fill(c) setfill(c) 設置填充宇符c
setf() setiosflags() 設置輸出格式狀態,括號中應給出格式狀態,內容與控制符setiosflags括號中的內容相同,如表13.5所示
unsetf() resetioflags() 終止已設置的輸出格式狀態,在括號中應指定內容


設置格式狀態的格式標誌
格式標誌 作用
ios::left 輸出數據在本域寬範圍內向左對齊
ios::right 輸出數據在本域寬範圍內向右對齊
ios::internal 數值的符號位在域寬內左對齊,數值右對齊,中間由填充字符填充
ios::dec 設置整數的基數爲10
ios::oct 設置整數的基數爲8
ios::hex 設置整數的基數爲16
ios::showbase 強制輸出整數的基數(八進制數以0打頭,十六進制數以0x打頭)
ios::showpoint 強制輸出浮點數的小點和尾數0
ios::uppercase 在以科學記數法格式E和以十六進制輸出字母時以大寫表示
ios::showpos 對正數顯示“+”號
ios::scientific 浮點數以科學記數法格式輸出
ios::fixed 浮點數以定點格式(小數形式)輸出
ios::unitbuf 每次輸出之後刷新所有的流
ios::stdio 每次輸出之後清除stdout, stderr

cout流的成員函數是在頭文件iostream 中定義的,因此只需包含頭文件iostream,不必包含iomanip。

例子:
cout.setf(ios::showbase);//顯示基數符號(0x或)
cout.unsetf(ios::dec); //終止十進制的格式設置

注意:

1.成員函數width(n)和控制符setw(n)只對其後的第一個輸出項有效。

2.在表13.5中的輸出格式狀態分爲5組,每一組中同時只能選用一種(例如dec、hex和oct中只能選一,它們是互相排斥的)。在用成員函數setf和控制符setiosflags設置輸出格式狀態後,如果想改設置爲同組的另一狀態,應當調用成員函數unsetf(對應於成員函數self)或resetiosflags(對應於控制符setiosflags),先終止原來設置的狀態。然後再設置其他狀態,大家可以從本程序中看到這點。程序在開始雖然沒有用成員函數self和控制符setiosflags設置用dec輸出格式狀態,但系統默認指定爲dec,因此要改變爲hex或oct,也應當先用unsetf 函數終止原來設置。如果刪去程序中的第7行和第10行,雖然在第8行和第11行中用成員函數setf設置了hex和oct格式,由於未終止dec格式,因此hex和oct的設置均不起作用,系統依然以十進制形式輸出。

3.用setf 函數設置格式狀態時,可以包含兩個或多個格式標誌,由於這些格式標誌在ios類中被定義爲枚舉值,每一個格式標誌以一個二進位代表,因此可以用位或運算符“|”組合多個格式標誌。如倒數第5、第6行可以用下面一行代替:
cout.setf(ios::internal | ios::showpos); //包含兩個狀態標誌,用"|"組合


做題記錄:AC

1.通過uvatoolkit 網站測試用例,把自己的程序結果與該網站給出的結果進行對比,由小尋找到程序的BUG。

2.做題時要把索引值和數據分開思考,雖然數據可能時連續的,但跟索引值意義完全不同,不分清這點很容易陷入思維誤區。

3.設計好數據結構後先考慮實現正確解決問題,再考慮優化問題,第一次提交的版本雖然獲得AC,但是明顯有優化空間,裏面有不少代碼重複並且邏輯可以優化。

4.具有相關關係的量,用同一個值表示,不要同時去操作兩個,這裏指N和circle.size()。

5.獲得AC後google瀏覽別的代碼學習。

代碼:

/**
 * @file id_133.cpp
 * @brief AOAPC I 133
 * @author chenxilinsidney
 * @version 1.0
 * @date 2015-03-28
 */

#include <iostream>
#include <string>
#include <vector>
#include <iomanip>

using namespace std;

int main()
{
    // get N, k m
    int N, k, m;
    while (cin >> N >> k >> m && N != 0) {
        cin.get();
        // create circle
        vector<int> circle;
        for (int i = 1; i <= N; i++)
            circle.push_back(i);
        // initialize index (index begin from 1 to N)
        int k_index = k;
        int m_index = N + 1 - m;
        while (N) {
            while (k_index < 0) k_index += N;
            while (k_index > N) k_index -= N;
            while (m_index < 0) m_index += N;
            while (m_index > N) m_index -= N;
            if (k_index == 0) k_index = N; 
            if (m_index == 0) m_index = N;
#ifndef ONLINE_JUDGE
            cout << "next " << k_index << " : " << m_index << endl;
#endif
            int first_remove = circle[k_index - 1];
            int second_remove = circle[m_index - 1];
            if (k_index != m_index) {
                if (k_index < m_index) {
                    // erase in sequence
                    circle.erase(circle.begin() + m_index - 1);
                    circle.erase(circle.begin() + k_index - 1);
                    // refresh index
                    k_index += k - 1;
                    m_index -= m + 1;
                } else {
                    // erase in sequence
                    circle.erase(circle.begin() + k_index - 1);
                    circle.erase(circle.begin() + m_index - 1);
                    // refresh index
                    k_index += k - 2;
                    m_index -= m;
                }
                // output
                cout << setw(3) << first_remove
                    << setw(3) << second_remove;
            } else {
                // erase
                circle.erase(circle.begin() + k_index - 1);
                // refresh index
                k_index += k - 1;
                m_index -= m;
                // output
                cout << setw(3) << first_remove;
            }
            // refresh circle size
            N = circle.size();
            if (N) cout << ",";
#ifndef ONLINE_JUDGE
            cout << "after dec: " << k_index << ","
                << m_index << "," << N << endl;
            for (size_t i = 0; i < circle.size(); i++)
                cout << "remain " << i << ":" << circle[i] << endl;
#endif
        }
        // output result
        cout << endl;
    }
    return 0;
}

4.673 - Parentheses Balance

知識點:括號匹配,用stack解決。(計算器實現,stack使用的典型案例)

做題記錄:WA -> AC

經過測試後,發現是讀取問題,cin >> string 並沒有正確處理空字符串,它會自動忽略空行,應該使用getline。

參考別人的代碼後可採取的優化措施(未去實現):

1.如果string長度是奇數,那麼是不可能匹配對的,因此可以快速輸出NO;

2.長度爲零時可以快速輸出YES.

3.必不需要遍歷整個string然後檢查size,在發現push的內容是‘)’或‘]'卻沒有在stack匹配到時就可以判斷出不可能匹配對,這時直接輸出NO。

代碼:

/**
 * @file id_673.cpp
 * @brief AOAPC I 673
 * @author chenxilinsidney
 * @version 1.0
 * @date 2015-03-29
 */

#include <iostream>
#include <string>
#include <vector>
#include <stack>

using namespace std;

bool ispair(char a, char b)
{
    return (a == '[' && b == ']') || (a == '(' && b == ')');
}
int main()
{
    int num_strings;
    cin >> num_strings;
    cin.get();
    string parantheses;
    while (num_strings--) {
        getline(cin, parantheses);
        stack<char> parantheses_stack;
        for (int i = 0; i < parantheses.size(); i++) {
            if (parantheses_stack.empty()) {
                parantheses_stack.push(parantheses[i]);
            } else {
                if (ispair(parantheses_stack.top(), parantheses[i]))
                    parantheses_stack.pop();
                else
                    parantheses_stack.push(parantheses[i]);
            }
        }
        if (parantheses_stack.empty())
            cout << "Yes" << endl;
        else
            cout << "No" << endl;
    }
    return 0;
}

5.442 - Matrix Chain Multiplication

知識點:矩陣乘法匹配:stack

技巧:

1.矩陣數據包括行和列,可以建立結構體聯立兩個。

1.已知矩陣用字母標記,可以利用map標記記錄每個矩陣信息。

也可以數組實現,效率更高:由於字母只有'A'-'Z',可以存儲到長度爲26的結構體數組中,對字母x利用(x - 'A')計算偏移即可獲得x在結構體數組中下標位置。

2.由於矩陣相乘總是成對的出現的,排除輸入爲單矩陣這種情況,在其他情況下,我們並不需要通過對‘(’和‘)’進行壓棧出棧記錄位置信息(利用堆棧實現計算器程序這種例子是必需的),每次只需要獲得棧頂2個矩陣即可(pop兩次)。

拓展:EBNF語法學習(閱讀題目或定義符號用到)

Extended Backus–Naur Form

(參考:http://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_Form)

Backus–Naur Form

(參考:http://en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form)

Table of symbols

Usage Notation
definition =
concatenation ,
termination  ;
termination . [1]
alternation |
option [ ... ]
repetition { ... }
grouping ( ... )
terminal string " ... "
terminal string ' ... '
comment (* ... *)
special sequence  ? ... ?
exception -

做題記錄: AC

6.11111 - Generalized Matrioshkas

知識點:stack。

從行中提取不定長的數組(包含正負):

A.C語言實現:

格式化IO:

char* line + fgets/gets + sscanf (<cstdio>, <cstring>獲得line長度)

C實現atoi函數:<cstdlib>

char* line + fgets/gets + atoi

B.C++ string + atoi

string + string.data() + offset + atoi

做題記錄: AC

7.11234 Expressions MARK

知識點:考察堆棧和隊列。考察二叉樹使用及不同遍歷方法。

技巧:表達式的識別,前綴表達式、中綴表達式、後綴表達式的獲得方法,解析。

做題記錄:TL -> TL -> WA -> AC

1.先用堆棧對表達式進行解析成表達式,再進行逆解析退回到隊列中,逆解析出來,超時。

2.參考別人的文章:題目要求重新寫出給出的後綴表達式,使原後綴表達式的棧方法和新表達式的隊列方法表示的表達式相同,也就是兩種表達式對應的表達式樹相等。

對比自己的思路可以發現,這道題我解析堆棧形式的後綴表達式時,翻譯成人類的語言,加括號,再進行逆解析,別人使用的是樹結構,不用考慮人看不看得懂,關鍵是存儲非常方便,這到題我思路主要侷限在棧和隊列的使用,並沒有很好的使用樹這種結構。

思路指引:

題目的最關鍵部分是進行二叉樹建樹, 以及層次遍歷逆序輸出,還有利用棧的“括號匹配”思想。 二叉樹的基本結構是,父結點都是操作符,子節點都是數字。 對於給出的序列, 從左到右遍歷,遇到代表數字的小寫則建立一個無兒子的樹,然後把根結點指針入棧, 遇到代表操作符的大寫字母,則從棧中彈出兩個根結點,然後建立一個以大寫字母爲根,彈出的兩個操作數爲左右兒子的樹,再把這個新樹的根結點指針壓入棧。如此循環下去。 最後,在棧頂的那個指針就是最後建成的樹的根結點。 然後對這顆樹進行層次遍歷把字母取出來,最後逆序輸出即可。

1.利用堆棧建立樹,葉子結點爲操作數,非葉子結點爲操作符。

2.利用隊列對樹進行層次遍歷。

其他:每行字符串較長,採用cstdio的gets函數讀取。

8.10050 - Hartals

知識點:數組

技巧:

1.採用位圖數據結構

2.while循環,加法替代不斷乘以相同係數的大批量乘法運算。速度優化:

舊:

int length = days / hartal + 1;
for (int i = 1; i <= length; i++)
day_log[1 + i * hartal] = 1;

新:

int length = hartal;
while (hartal <= days) {
day_log[1 + hartal] = 1;
hartal += length;
}

做題記錄: AC

9.540 - Team Queue

知識點:根據數據範圍及提點,利用位圖數據結構,建立關聯數組實現常數時間訪問;數組隊列實現。

特點:這道題要通過位圖數據結構實現常量時間的處理。

做題記錄: RE -> 尚未解決。

10.10152 - ShellSort MARK

關鍵理解部分:

http://www.algorithmist.com/index.php/UVa_10152

It seems as though King Yertle has set a tough task for you, but trying a few examples on paper should lead you to the following insights:

  • A turtle doesn't have to move if it is already above all the turtles it is supposed to be above. Otherwise, it must move.
  • If a turtle moves to the top, then the turtle that is supposed to be directly above it must also move.
  • Applying this recursively, this means if turtle x must move, then turtles x-1,x-2,x-3,\ldots ,1 must also move, in that order.

So, the problem boils down to finding the lowest (in terms of placement on the wanted order of the stack) turtle that must move, and printing its name and the name of every turtle above it in the wanted ordering of the stack.

沒有理清思路的地方:思考序列如何選擇turtle什麼時候移動,我們通過堆棧可以快速判斷出要移動的turtle,但是自己沒思路去判斷,怎麼選擇這些順序。認真考慮上面哪句話的含義,在確定次序時,如果我們先移動小的x turtle再移動大的X turtle,那麼小的x turtle必然需要再移動一次,因爲X turtle移動後,比他要小的x turtle必然需要再移動一次才能使隊列正確排序,因此,我們可以得出結論,確定所有要移動的turtle後,按次序先移動大turtle再移動小turtle即可。(假設目標時turtle從小到大排列)

這種思考方式:通過選擇對象之間的相互關係或作用效果分析不同選擇方式對問題造成的影響,從而尋找最優解。

其他:

如果線性表設計到較少的數據刪除和插入,string並不總是需要用vector容器,數組形式的string a[100]效率更高,本題如此。

針對這個問題,stack可以被索引/指針下表指示法高效替代,效率更高。

做題記錄: google -> AC

拓展:

1.本題的排序方法跟通常定義的希爾排序算法並不一樣,希爾排序見:http://blog.csdn.net/chensilly8888/article/details/42591861

希爾排序是插入排序的變種。

插入排序用的比較的元素總是以距離一爲單位減小並逐個比較,而希爾排序使用的這裏距離gap是變化的,它逐漸減小這個gap並通過對序列進行多次循環從而進行排序。



其他總結:

1.使用stack,要考慮好push和pop的數據什麼纔是最好的,設計好這一步,可以簡化算法並有效利用stack。

代碼:

https://github.com/chenxilinsidney/funnycprogram/tree/master/acm/aoapc



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章