OVa Online Judge 學習筆記- AOAPC I Volume 1. Sorting/Searching

一、題目

二、做題筆記

1.10420 - List of Conquests

知識點:字符串排序,及相似字符串統計。

題目和10815相當類似,稍微修改下輸出和讀取格式即可。(C版本,使用qsort進行排序,自己實現用於比較字符串的compare函數)

答題記錄:AC

拓展:可以寫C++版本,調用<algorithm>中的sort函數進行排序。

2.10474 - Where is the Marble?

知識點:整數排序,使用qsort.

答題記錄:AC

3.152 - Tree's a Crowd

知識點:整數最值,可以通過過濾範圍外的數減少遍歷計算量。

同時,查找某數平方根的範圍區間時,若數量較少,可以採用表查找該數:list = 0,1,4,9,16,25..找到索引位置可得到該數平方根區間,從而避免開方運算。

答題記錄:AC

4.299 - Train Swapping

知識點:考察交換排序。

答題記錄:AC

5.120 - Stacks of Flapjacks

知識點:排序。

答題記錄:WA

對題目理解錯誤,題目的排序要求整個序列都是有序的(sort),而不是隻要求最大最小值在兩端。

6.156 - Ananagrams

知識點:字符串排序,包括:字符大小寫轉換、字符小寫字母排序,字符混合字母排序,字符串查重,由於每個字符串用到的信息比較多,因此建立一個結構體存儲各狀態並關聯。

C優化:排序時要求大寫在前,小寫在後,根據ASCII碼錶,我們可以發現‘A‘ < 'Z' < 'a' < 'z';按照ASCII值排序即可,說明strcmp已經做好了這方面的工作,大小寫排序不需要做特殊處理。

因此,可以建立結構體排序,處理後字母優先級爲一,處理前字母優先級爲二。

C++學習:

數據特點:字符串經過處理後,我們保留的字符串是不重複的並且只需要處理前的字符串,對於處理後出現重複的字符串我們並不需要。

可以利用vector和map配合快速解決問題:

1.第一種:使用multimap<string,string>(採用處理後字符串作爲鍵,可能重複,故不能使用map)。map會自動排序。

利用multimap.count方法找到值個數唯一的那麼處理前字符,再加入vector進行排序。

2.第二種:使用map<string,int>統計處理後字符串個數。

找到個數唯一的string,與排好序後的原字符串vector配合。

7.400 - Unix ls

技巧:考察字符串排序,數據輸出排版。

C版本:

若考慮浮點數精度問題:<float.h>

DBL_EPSILON:若直接取整加上這個偏差。若四捨五入加上0.5。

參考別人的答案時,發現並沒有做精度處理也能得到AC。

C++學習:

1.cin如何判斷文件結尾:

while( cin >> tmp ) cout << tmp << endl ;

2.採用vector和sort對數據進行存儲和排序。

模板容器類vector <vector>

vector(向量): C++中的一種數據結構,確切的說是一個類。它相當於一個動態的數組,當程序員無法知道自己需要的數組的規模多大時,用其來解決問題可以達到最大節約空間的目的。

數組的缺點是分配空間不靈活;鏈表的缺點是無法通過下標快速找到結點。然而這裏介紹的向量卻吸收了這兩種數據結構各自的優點,綜合性能較高。向量的分配空間是會隨着數據的量而變化的,如果空間不夠,那麼向量的空間會自動增長。類似於數組,我們也可以通過下標來訪問向量中的數據元素,增快找到數據的速度。

vector其中一個特點:內存空間只會增長,不會減小,援引C++ Primer:爲了支持快速的隨機訪問,vector容器的元素以連續方式存放,每一個元素都緊挨着前一個元素存儲。設想一下,當vector添加一個元素時,爲了滿足連續存放這個特性,都需要重新分配空間、拷貝元素、撤銷舊空間,這樣性能難以接受。因此STL實現者在對vector進行內存分配時,其實際分配的容量要比當前所需的空間多一些。就是說,vector容器預留了一些額外的存儲區,用於存放新添加的元素,這樣就不必爲每個新元素重新分配整個容器的內存空間。

在調用push_back時,每次執行push_back操作,相當於底層的數組實現要重新分配大小;這種實現體現到vector實現就是每當push_back一個元素,都要重新分配一個大一個元素的存儲,然後將原來的元素拷貝到新的存儲,之後在拷貝push_back的元素,最後要析構原有的vector並釋放原有的內存。

8.123 - Searching Quickly

技巧:考察排序,字符串匹配,大小寫轉換。

C版本優化:

1.C語言調用qsort進行排序,所排序爲字符串排序,排序比較函數裏直接調用strcmp,不用自己些字符串比較函數。

2.字符串大小轉換調用tolower,toupper (C++中也是如此),寫成獨立函數,方便以後再次調用。

C++版本優化:

使用模板容器類multimap:<map> map:鍵值不能重複,multimap:鍵值可以重複,排序嚴格按照插入先後順序。

(分析:這道題也是處理字符串之間匹配,可以用字符串作爲鍵值找到記錄,multimap解決輸出時相同字符串先找到先輸出的問題,使用multimap處理多鍵值情況。)

插入map時使用make_pair(a,b) 或 pair<type_a, type_b>(a,b)

使用模板容器類set存儲集合,這些數據必須是唯一的。(反應出數據特點:互不相同;)<set>

(分析:題目中ignore單詞列表都是唯一的,後面用於搜索,可採用set存儲)

set 和 map 比較:

MAP的節點是一對數據.
SET的節點是一個數據.

set(集合)——包含了經過排序了的數據,這些數據的值(value)必須是唯一的。

map(映射)——經過排序了的二元組的集,map中的每個元素都是由兩個值組成,其中的key(鍵值,一個map中的鍵值必須是唯一的)是在排序或搜索時使用,它的值可以在容器中重新獲取;而 另一個值是該元素關聯的數值。比如,除了可以ar[43] = "overripe"這樣找到一個數據,map還可以通過ar["banana"] = "overripe"這樣的方法找到一個數據。如果你想獲得其中的元素信息,通過輸入元素的全名就可以輕鬆實現。

9.10194 - Football (aka Soccer)

技巧:

1.這道題數據較多,可以建立結構體存儲相關數據。

2.C語言qsort算法中排序比較算法,能夠通過比較函數利用結構體個關鍵字數據實現多個關鍵字排序(根據不同關鍵字不同優先級順序)。

3.C語言使用qsort和bsearch配合,進行快速查找

4.scanf中讀取字符串參數[xxx]使用:完成字符串中讀取子字符串功能。

舊方法:掃描字符串到某分割符,在把這個區間memcpy到新字符串中。代碼步驟較多。

新方法:使用[xxx]參數(留意^符號),可用於scanf,sscanf,fsancf。

C++學習:

獲取單個字符(可用於丟棄字符):

char_a = cin.get();

獲取單個字符串:

cin >> string_a(string string_a);(遇到空白字符結束)

cin >> char_a (char char_a[10]);(遇到空白字符結束)

獲取單行:

cin.getline(char_a,10),超過後結尾會添加'\0';(istream 流)

getline(cin,string_A) (遇到換行符\n或指定字符截止,並在流中捨棄該字符)(string流)

數據轉換:

cstdlib中,將字符串轉換成整數、浮點數等,可用於讀取字符串中特定數據類型。atoi ....

自定義比較函數用於排序:

sort <algorithm> 注意這裏的比較函數和qsort比較函數不同,返回bool值,大於0表示排前面,並且參數用引用變量,不必類型轉換。

字符串比較:(strcmp另一種)

C:

頭文件:#include <string.h>
定義函數:int strcasecmp (const char *s1, const char *s2);
函數說明:strcasecmp()用來比較參數s1 和s2 字符串,比較時會自動忽略大小寫的差異。

使用模板容器類map:<map>

(C版本中解決問題過程中匹配數組名時採用nlgn快速排序(qsort)後再採用lgn二分查找(bsearch),C++版本map可以關聯鍵值對,利用鍵值實現快速檢索(lgn),通過鍵值快速找到記錄,而不必先排序,這也時本題使用map的原因。)

Map是標準關聯式容器(associative container)之一,一個map是一個鍵值對序列,即(key ,value)對。它提供基於key的快速檢索能力,在一個map中key值是唯一的。map提供雙向迭代器,即有從前往後的(iterator),也有從後往前的(reverse_iterator)。

map要求能對key進行<操作,且保持按key值遞增有序,因此map上的迭代器也是遞增有序的。如果對於元素並不需要保持有序,可以使用hash_map。

10.487--3279

技巧:查表法。快速找到索引值(數據初始長度雖然不爲零不與首元素下標對應,但長度有限可以加入偏移修正)

問題:C代碼一直報RUNTIME ERROR 原因未解。

11.10785 - The Mad Numerologist

技巧:

1.查表法,從表中快速選取相應的字符串。

進一步優化:由於問題規模n有限,對於每一n獲得的數據的前n-1個數據與問題規模n-1下的數據相同,可以建立個全表,避免根據n選取單個字符到字符串中。

優化前:

(小表)字符串根據n按照規則選取下面字符到字符串中:

char* vowel_list = "AUEOI";
char* consonant_list = "JSBKTCLDMVNWFXGPYHQZR";

優化後:

(大表)直接根據問題規模n在下面字符串中選取長度爲n的字符串:(事先生成結果)

char* letter_list = "AJAJAJAJAJASASASASASABABABABABAKAKAKAKAKATUTUTUTUTUCUCUCUCUCULULULULULUDUDUDUDUDUMUMEMEMEMEVEVEVEVEVENENENENENEWEWEWEWEWEFEFEFOFOFOXOXOXOXOXOGOGOGOGOGOPOPOPOPOPOYOYOYOYIYIHIHIHIHIHIQIQIQIQIQIZIZIZIZIZIRIRIRIRIR";

根據問題需要建立下面兩個奇偶位相關的表排序會更快:

string vowel_list =

"JJJJJSSSSSBBBBBKKKKKTTTTTCCCCCLLLLLDDDDDMMMMMVVVVVNNNNNWWWWWFFFFFXXXXXGGGGGPPPPPYYYYYHHHHHQQQQQZZZZZRRRRR";

string consonant_list =

"AAAAAAAAAAAAAAAAAAAAAUUUUUUUUUUUUUUUUUUUUUEEEEEEEEEEEEEEEEEEEEEOOOOOOOOOOOOOOOOOOOOOIIIIIIIIIIIIIIIIIIIII";

2.排序算法:

C:由於奇偶位按照不同的規則分開排序,因此奇偶位需要分開作爲兩種數據分別按照不同規則處理,若調用qsort函數,需要使用數據兩次,通過兩種不同的比較函數調用兩次qsort排序,再將結果整合起來。(將字符串從奇偶位分開建立,分開排序,再按要求輸出)

C++學習(C版本AC後寫C++版本):

使用string類字符串:<string>

string 獲取子串方法名:substr;

string 排序(調用sort <algorithm>):sort(vowel.begin(), vowel.end());

string 獲取首尾元素:back() front() (<<--- 注意:前兩個爲C++11標準,gcc 編譯選項需要加上std=c++11)。其他獲取元素方法:operator[] ; at(i)(小結:string獲取元素共有的四個方法)

C++代碼:

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

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

string vowel_list = "AAAAAAAAAAAAAAAAAAAAAUUUUUUUUUUUUUUUUUUUUUEEEEEEEEEEEEEEEEEEEEEOOOOOOOOOOOOOOOOOOOOOIIIIIIIIIIIIIIIIIIIII";
string consonant_list = "JJJJJSSSSSBBBBBKKKKKTTTTTCCCCCLLLLLDDDDDMMMMMVVVVVNNNNNWWWWWFFFFFXXXXXGGGGGPPPPPYYYYYHHHHHQQQQQZZZZZRRRRR";

int main()
{
    int num_case;
    cin >> num_case;
    for (int index_case = 1; index_case <= num_case; index_case++) {
        // input length
        int length;
        cin >> length;
#ifndef ONLINE_JUDGE
        cout << "length = " << length << endl;
#endif
        int count_even = length / 2;
        int count_odd = length - count_even;
        string vowel = vowel_list.substr(0, count_odd);
        string consonant = consonant_list.substr(0, count_even);
        sort(vowel.begin(), vowel.end());
        sort(consonant.begin(), consonant.end());
        cout << "Case " << index_case << ": ";
        for (int i = 0; i < count_even; i++)
            cout << vowel[i] << consonant[i];
        if (count_odd > count_even)
            cout << vowel.back();
        cout << endl;
    }
    return 0;
}

其他總結:

1.宏定義:ONLINE_JUDGE 輔助調試,網站GCC 編譯是會加入-DONLINE_JUDGE現象 (-Dxx 表示編譯器編譯時會宏定義xx)

2.善用C++ STL:vector map 等使用。

3.善用結構體。

4.C和C++都值得實現並進行測試。

公開:

程序代碼地址:https://github.com/chenxilinsidney/funnycprogram/tree/master/acm/aoapc

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