第一章:環境構築から始めよう
プログラミングを始める前に、まず開発環境を整える必要があります。OI(情報学オリンピック)では、Dev-C++、Code::Blocks、VS CodeなどのIDEが一般的です。初心者はDev-C++から始めることをおすすめします。軽量で設定も簡単なため、初心者には適しています。
1.1 Dev-C++のインストール手順
- 「Dev-C++」を検索し、公式サイトを確認してください(広告に注意)。
- ダウンロード後、インストーラーを実行し、デフォルト設定でインストールします。
- インストール完了後、ファイル→新規→ソースファイルを開き、準備完了です。
1.2 最初のプログラム:「Hello World」
#include <iostream>
using namespace std;
int main()
{
cout << "Hello OI! I'm coming!" << endl;
return 0;
}
このコードは、標準出力を使って「Hello OI! I'm coming!」と表示するものです。各要素について説明します:
#include <iostream>:入出力機能を提供するライブラリを読み込みます。using namespace std;:標準名前空間を使用することを宣言します。int main():プログラムのエントリーポイントです。cout << ... << endl;:画面に出力します。return 0;:正常終了を示します。
第二章:C++の基本文法
2.1 変数の使い方
変数とはデータを格納するための箱のようなものです。以下のように定義できます:
int a; // 整数型
double b; // 浮動小数点型
char c; // 文字型
bool d; // 真偽値型
初期化は以下の通りです:
int a = 10;
double b = 3.14159;
char c = 'O';
bool d = true;
2.2 データ型の種類
| 型 | 用途 | 範囲 | 例 |
|---|---|---|---|
| int | 整数 | -20億〜20億 | 10、-500 |
| long long | 大きな整数 | -9e18〜9e18 | 12345678901234 |
| double | 浮動小数点(倍精度) | 約15桁 | 3.14、0.0001 |
| float | 浮動小数点(単精度) | 約6桁 | 1.23f |
| char | 文字 | ASCIIコード | 'A'、'5'、'+' |
| bool | 真偽値 | true/false | true |
2.3 演算子
算術演算子
int x = 10, y = 3;
cout << x + y << endl; // 13
cout << x - y << endl; // 7
cout << x * y << endl; // 30
cout << x / y << endl; // 3(整数除算)
cout << x % y << endl; // 1(剰余)
代入演算子
int a = 5;
a += 3; // a = a + 3
a -= 2; // a = a - 2
a *= 4; // a = a * 4
a /= 6; // a = a / 6
a %= 3; // a = a % 3
比較演算子
int x = 5, y = 8;
cout << (x > y) << endl; // false(0)
cout << (x < y) << endl; // true(1)
cout << (x == y) << endl; // false(0)
cout << (x != y) << endl; // true(1)
cout << (x >= y) << endl; // false(0)
cout << (x <= y) << endl; // true(1)
論理演算子
bool a = true, b = false;
cout << (a && b) << endl; // false(0)
cout << (a || b) << endl; // true(1)
cout << (!a) << endl; // false(0)
2.4 入出力
#include <iostream>
using namespace std;
int main()
{
int a;
double b;
char c;
cout << "入力してください:" << endl;
cin >> a >> b >> c;
cout << "整数:" << a << endl;
cout << "小数:" << b << endl;
cout << "文字:" << c << endl;
return 0;
}
2.5 分岐構造
if文
#include <iostream>
using namespace std;
int main()
{
int score;
cout << "点数を入力:" << endl;
cin >> score;
if (score >= 90)
cout << "優秀!" << endl;
else if (score >= 80)
cout << "良好!" << endl;
else if (score >= 60)
cout << "合格!" << endl;
else
cout << "不合格!" << endl;
return 0;
}
switch文
#include <iostream>
using namespace std;
int main()
{
int day;
cout << "曜日を入力(1-7):" << endl;
cin >> day;
switch (day)
{
case 1: cout << "月曜日" << endl; break;
case 2: cout << "火曜日" << endl; break;
case 3: cout << "水曜日" << endl; break;
case 4: cout << "木曜日" << endl; break;
case 5: cout << "金曜日" << endl; break;
case 6: cout << "土曜日" << endl; break;
case 7: cout << "日曜日" << endl; break;
default: cout << "無効" << endl;
}
return 0;
}
2.6 繰り返し構造
for文
#include <iostream>
using namespace std;
int main()
{
for (int i = 1; i <= 10; i++)
cout << i << " ";
return 0;
}
while文
#include <iostream>
using namespace std;
int main()
{
int sum = 0, n = 0;
while (sum <= 1000)
{
n++;
sum += n;
}
cout << "n=" << n << "で和が1000を超える" << endl;
return 0;
}
do-while文
#include <iostream>
using namespace std;
int main()
{
int x = 0;
do
{
cout << "Hello" << endl;
x++;
} while (x > 1);
return 0;
}
2.7 配列
int a[10]; // 10個の整数
double b[5]; // 5個の小数
char c[20]; // 20個の文字
2.8 文字列
#include <string>
using namespace std;
int main()
{
string s1; // 空文字列
string s2 = "OI"; // 初期化
string s3 = s2; // コピー
string s4(5, 'a'); // "aaaaa"
return 0;
}
2.9 関数
#include <iostream>
using namespace std;
int add(int x, int y)
{
return x + y;
}
int main()
{
int a = 5, b = 3;
int sum = add(a, b);
cout << "5+3=" << sum << endl;
return 0;
}
2.10 ポインタ
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int *p = &a;
cout << "aの値:" << a << endl;
cout << "pの値:" << p << endl;
cout << "*pの値:" << *p << endl;
*p = 20;
cout << "変更後のa:" << a << endl;
return 0;
}
第三章:アルゴリズム入門
3.1 総当たり法
#include <iostream>
using namespace std;
int main()
{
cout << "3と5で割り切れる数:" << endl;
for (int i = 1; i <= 100; i++)
if (i % 3 == 0 && i % 5 == 0)
cout << i << " ";
return 0;
}
3.2 検索アルゴリズム
線形探索
#include <iostream>
using namespace std;
int search(int a[], int n, int target)
{
for (int i = 0; i < n; i++)
if (a[i] == target) return i;
return -1;
}
int main()
{
int a[5] = {10, 20, 30, 40, 50};
int pos = search(a, 5, 30);
if (pos != -1) cout << "見つかった:" << pos << endl;
return 0;
}
二分探索
#include <iostream>
using namespace std;
int binary_search(int a[], int n, int target)
{
int l = 0, r = n - 1;
while (l <= r)
{
int mid = (l + r) / 2;
if (a[mid] == target) return mid;
else if (a[mid] > target) r = mid - 1;
else l = mid + 1;
}
return -1;
}
int main()
{
int a[5] = {10, 20, 30, 40, 50};
int pos = binary_search(a, 5, 40);
if (pos != -1) cout << "見つかった:" << pos << endl;
return 0;
}
3.3 ソートアルゴリズム
バブルソート
#include <iostream>
using namespace std;
void bubble_sort(int a[], int n)
{
for (int i = 0; i < n - 1; i++)
for (int j = 0; j < n - 1 - i; j++)
if (a[j] > a[j + 1])
{
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
int main()
{
int a[5] = {3, 1, 4, 2, 5};
bubble_sort(a, 5);
for (int i = 0; i < 5; i++) cout << a[i] << " ";
return 0;
}
選択ソート
#include <iostream>
using namespace std;
void select_sort(int a[], int n)
{
for (int i = 0; i < n - 1; i++)
{
int min_pos = i;
for (int j = i + 1; j < n; j++)
if (a[j] < a[min_pos]) min_pos = j;
int temp = a[i];
a[i] = a[min_pos];
a[min_pos] = temp;
}
}
int main()
{
int a[5] = {3, 1, 4, 2, 5};
select_sort(a, 5);
for (int i = 0; i < 5; i++) cout << a[i] << " ";
return 0;
}
挿入ソート
#include <iostream>
using namespace std;
void insert_sort(int a[], int n)
{
for (int i = 1; i < n; i++)
{
int temp = a[i];
int j = i - 1;
while (j >= 0 && a[j] > temp)
{
a[j + 1] = a[j];
j--;
}
a[j + 1] = temp;
}
}
int main()
{
int a[5] = {3, 1, 4, 2, 5};
insert_sort(a, 5);
for (int i = 0; i < 5; i++) cout << a[i] << " ";
return 0;
}
3.4 再帰と反復
再帰
#include <iostream>
using namespace std;
int fib(int n)
{
if (n == 1 || n == 2) return 1;
return fib(n - 1) + fib(n - 2);
}
int main()
{
int n;
cout << "nを入力:" << endl;
cin >> n;
cout << "fib(" << n << ")=" << fib(n) << endl;
return 0;
}
反復
#include <iostream>
using namespace std;
int main()
{
int n;
cout << "nを入力:" << endl;
cin >> n;
if (n == 1 || n == 2)
{
cout << "1" << endl;
return 0;
}
int a = 1, b = 1, c;
for (int i = 3; i <= n; i++)
{
c = a + b;
a = b;
b = c;
}
cout << c << endl;
return 0;
}
3.5 前処理和(累積和)
#include <iostream>
using namespace std;
int main()
{
int n, m;
cout << "配列長とクエリ数:" << endl;
cin >> n >> m;
int a[1000], s[1001] = {0};
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) s[i] = s[i - 1] + a[i - 1];
for (int i = 0; i < m; i++)
{
int l, r;
cin >> l >> r;
cout << "区間[" << l << "," << r << "]の和:" << s[r + 1] - s[l] << endl;
}
return 0;
}
第四章:実践問題
4.1 最大公約数(GCD)
#include <iostream>
using namespace std;
int gcd(int a, int b)
{
while (b != 0)
{
int temp = b;
b = a % b;
a = temp;
}
return a;
}
int main()
{
int a, b;
cout << "2つの整数を入力:" << endl;
cin >> a >> b;
cout << "最大公約数:" << gcd(a, b) << endl;
return 0;
}
4.2 素数判定
#include <iostream>
#include <cmath>
using namespace std;
bool is_prime(int n)
{
if (n <= 1) return false;
if (n == 2) return true;
if (n % 2 == 0) return false;
for (int i = 3; i <= sqrt(n); i += 2)
if (n % i == 0) return false;
return true;
}
int main()
{
int n;
cout << "整数を入力:" << endl;
cin >> n;
if (is_prime(n)) cout << n << "は素数" << endl;
else cout << n << "は素数ではない" << endl;
return 0;
}
4.3 二次元累積和
#include <iostream>
using namespace std;
const int N = 1010;
int a[N][N], s[N][N];
int main()
{
int n, m, q;
cout << "行数、列数、クエリ数:" << endl;
cin >> n >> m >> q;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> a[i][j];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
s[i][j] = a[i][j] + s[i-1][j] + s[i][j-1] - s[i-1][j-1];
while (q--)
{
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
int sum = s[x2][y2] - s[x1-1][y2] - s[x2][y1-1] + s[x1-1][y1-1];
cout << "和:" << sum << endl;
}
return 0;
}
4.4 フィボナッチ数列(再帰と反復)
#include <iostream>
using namespace std;
int main()
{
int n;
cout << "階数を入力:" << endl;
cin >> n;
if (n == 1 || n == 2)
{
cout << "1" << endl;
return 0;
}
int a = 1, b = 1, c;
for (int i = 3; i <= n; i++)
{
c = a + b;
a = b;
b = c;
}
cout << c << endl;
return 0;
}
第五章:避けるべき落とし穴と進歩の方向
5.1 常見なミス
- 分号の欠落
- 中括弧の不一致
- 変数の初期化不足
- 配列の境界外アクセス
- 整数のオーバーフロー
5.2 デバッグテクニック
- coutによる変数出力
- コメントによるコードの切り分け
- 境界値のテスト
- コンパイラエラーの解釈
5.3 進級のステップ
- 基礎:スタック、キュー、連結リスト
- 中級:ツリー、ヒープ、Union-Find
- 上級:セグメント木、BIT、グラフアルゴリズム
第六章:まとめ
この記事を通じて、C++の基本文法やアルゴリズムの基礎知識を学びました。今後は、これらの知識をもとに実践的な問題を解いていくことで、さらにスキルを磨いていきましょう。