競技プログラミング風 標準C++ライブラリ入門【第10回】
今回も、標準C++ライブラリの基本をマスターするための競技プログラミング風問題を解いていただこう。
問題を理解したら、テストコードをコンパイル・実行していただきたい。そのままだと実行時に「NG」が表示される。 コードを完成させ、「Good Job!」を表示させてすっきりしてほしい。グッドラック!
目次
加算関数(難易度:★★☆☆☆)
int型引数2つを取り、その和を返す関数オブジェクトを返す関数 function
例えば、「auto f = addFunc();」で加算関数オブジェクトを作成後に、f(1,2) を実行すると 3 を返す。
#include <iostream> // 標準入出力ライブラリ #include <functional> using namespace std; // std 名前空間使用 #define DO_TEST(exp) do_test(exp, __LINE__) void do_test(bool b, int line) { if( b ) return; // OK cout << "\nNG at line " << line << "\n"; exit(1); } function<int (int, int)> addFunc() { return nullptr; // ToDo: 標準関数を使い、ここを書き換え、加算関数オブジェクトを返す } int main() { auto f = addFunc(); DO_TEST(f != nullptr); DO_TEST( f(123, 456) == 579); cout << "\nGood Job!\n"; return 0; }
途中取り出し(難易度:★★☆☆☆)
string型第1引数strのix番目からlen文字を文字列として返す関数 string my_mid(const string& str, int ix, int len) を実装しなさい。
先頭文字からの場合、ix: 0 とする。ix がマイナスの値の場合は、末尾から前に向かってlen文字を文字列として返すものとする。
例えば my_mid(“abcde”, 0, 3) は “abc” を、my_mid(“abcde”, -1, 3) は “cde” を返す。
my_mid(“abc”, 5, 2) や my_mid(“abc”, -5, 2) の様に、ix が範囲外の場合は “” を返すものとする。
また、len が長すぎる場合は、有効な長さまでの文字列を返すものとする。例えば my_mid(“abc”, 2, 3) は “c” を返す。
#include <iostream> // 標準入出力ライブラリ #include <string> using namespace std; // std 名前空間使用 #define DO_TEST(exp) do_test(exp, __LINE__) void do_test(bool b, int line) { if( b ) return; // OK cout << "\nNG at line " << line << "\n"; exit(1); } string my_mid(const string& str, int ix, int len) { // ToDo: 標準関数を使い、ここを書き換えて、str の ix 番目から len 文字を返す // ix がマイナス値の場合は末尾からix文字目から、先頭に向かって len 文字を返す return ""; } int main() { DO_TEST( my_mid("123", 1, 1) == "2" ); DO_TEST( my_mid("abcde", -1, 2) == "de" ); DO_TEST( my_mid("123", 5, 1) == "" ); DO_TEST( my_mid("123", -5, 1) == "" ); DO_TEST( my_mid("123", 2, 3) == "3" ); DO_TEST(my_mid("123", -3, 3) == "1"); cout << "\nGood Job!\n"; return 0; }
シャフル(難易度:★★☆☆☆)
要素数52の(トランプの)カードデッキ配列を引数で受け取り、要素をシャフル(カード順序をランダムにする)する関数 void my_shuffle(vector<int>& deck) を実装しなさい。
なお、各カードの値は 0~51 で、値を13で割った商はクローバ・スペード・ハート・ダイヤモンドを表し、 値を13で割った剰余はカードの数字-1を表す(0-12 が A, 2,… Q, K を表す)ものとする。 具体的には、値0はクラブのエースを、値14はスペードの2を、値51はダイヤモンドのKを表す。
また、シャフルするために乱数を使用する場合は、テストコードで定義している g_mt() を使用しなさい。
#include <iostream> // 標準入出力ライブラリ #include <vector> #include <random> using namespace std; // std 名前空間使用 std::random_device g_rnd; // 非決定的な乱数生成器 std::mt19937 g_mt(g_rnd()); // メルセンヌ・ツイスタの32ビット版乱数生成関数 #define DO_TEST(exp) do_test(exp, __LINE__) void do_test(bool b, int line) { if( b ) return; // OK cout << "\nNG at line " << line << "\n"; exit(1); } const int N_CARD = 52; // 13*4, カード種類数 bool isShuffled(const vector<int>& deck) { // カードがシャフルされているか判定 vector<int> vc(52, 0); int mx = 0; for(int i = 1; i != deck.size(); ++i) mx = max(mx, vc[abs(deck[i-1] - deck[i])] += 1); return mx < 8; } void my_shuffle(vector<int>& deck) { // ToDo: 標準関数を使い、ここを書き換えて、deck の要素をシャフルする } int main() { vector<int> deck; for(int i = 0; i != N_CARD; ++i) deck.push_back(i); DO_TEST( !isShuffled(deck) ); my_shuffle(deck); DO_TEST( isShuffled(deck) ); cout << "\nGood Job!\n"; return 0; }
競技プログラミング風 標準C++ライブラリ入門 連載目次リンク
![]() |
筆者:津田伸秀 プロフィール:テニス・オセロ・ボードゲーム・パズル類が趣味の年齢不詳のおじさん。 自宅研究員(主席)。vi と C++が好き。迷走中・・・ ボードゲーム・パズル系アプリ開発・リリースしてます。 |