-
C++によるエドモンズ・カープ(Edmonds-Karp)アルゴリズムの実装:最大流を計算するプログラム
本記事では、C++を用いてエドモンズ・カープ(Edmonds-Karp)アルゴリズムを実装し、グラフの始点(ソース)から終点(シンク)までの最大流(Maximum Flow)を計算する方法を解説します。 アルゴリズムの概要 エドモンズ・カープ法は、フォード・ファルカーソン法を改良したアルゴリズムで、増加経路(Augmenting Path)の探索に幅優先探索(BFS)を採用している点が特徴です。常に最短の増加経路から流量を確定していくため、計算量は O(V・E²) に抑えられます。 Begin function edmondsKarp() : 流量を 0 に初期化する。
-
【C++】1次元オブジェクトとMビンのFirst Fit Decreasing(FFD)アルゴリズムを実装する方法
本記事では、1次元のオブジェクトをM個のビン(容器)に詰める「First Fit Decreasing(ファーストフィット・ディクリーシング)」アルゴリズムをC++で実装するプログラムを紹介します。 First Fit Decreasingとは First Fit Decreasing(FFD)は、ビンパッキング問題に対する代表的な近似解法の一つです。基本的な流れは次のとおりです。 すべてのアイテムをサイズの降順に並べ替える。 各アイテムについて、残り容量が足りている最初のビンへ順番に格納していく。 どの既存ビンにも収まらない場合は、新しいビンを用意する。 大きいアイテムから先に詰めるこ
-
【C++】スタックを使ってヒストグラム内の最大長方形領域を効率的に求める方法
本記事では、C++を用いてヒストグラムの中から面積が最大となる長方形領域を見つけるプログラムを紹介します。この問題は、各バーの高さが与えられたヒストグラムにおいて、隣接するバーで構成できる最大の長方形の面積を求めるという、アルゴリズムの定番問題の一つです。getArea()関数のアルゴリズムこのアルゴリズムはスタックを活用することで、時間計算量O(n)という高效な処理を実現しています。基本的な流れは以下の通りです。空のスタックを作成し、最大面積(largest_area)を0で初期化します。最初のバーから順に、すべてのバー hist[i](i = 0 〜 n-1)について以下の処理を繰り返しま
-
C++でstd::stringをLPCSTRに変換する方法を解説
LPCSTRとは何かこの記事では、C++の文字列クラスであるstd::stringを、LPCSTR型に変換する方法を詳しく解説します。LPCSTRは「Long Pointer to Constant STRing(定数文字列へのロングポインタ)」の略称で、C言語スタイルのヌル終端文字列を指す型です。LPCSTRはMicrosoftが定義した型であるため、プログラム内で使用するにはWindows.hヘッダーファイルをインクルードする必要があります。std::stringを文字配列に変換することで、LPCSTRとして扱えるようになります。c_str()関数を使った変換方法std::stringをC
-
C++でstd::wstringをLPCWSTRに変換する方法
この記事では、C++のワイド文字列(std::wstring)をLPCWSTRに変換する方法について詳しく解説します。LPCWSTRとは何かLPCWSTRは「Long Pointer to Constant Wide STRing(定数ワイド文字列へのロングポインタ)」の略称で、Microsoftが定義したWindows API用のデータ型です。名前の通り、ワイド文字(wchar_t)で構成された読み取り専用の文字列を指すポインタとして機能します。そのため、LPCWSTRを使用するには、プログラムにWindows.hヘッダーファイルをインクルードする必要があります。変換の基本的な考え方LPCW
-
C言語でstring.hとループを使わずに文字列の長さを求める方法
この記事では、C言語においてstring.hヘッダーファイルとループを使わずに文字列の長さを求める方法を解説します。文字列の長さを取得する問題は、string.hを使わなくても非常に簡単に解決できます。一般的には再帰関数を利用する手法が知られていますが、今回は再帰を使わない別のテクニックを紹介します。その鍵となるのがprintf()関数の戻り値です。printf()関数は、実際に出力した文字数を返り値として返します。この性質を利用すれば、文字列をprintf()で出力するだけで、その文字数、すなわち文字列の長さを簡単に取得できるのです。サンプルコード#include<stdio.h>
-
C言語の文字列化演算子(#)とトークン貼り付け演算子(##)を徹底解説
C言語のプリプロセッサには、マクロ定義をより柔軟に扱うための特殊な演算子が用意されています。本記事では、その中でも重要な「文字列化演算子(#)」と「トークン貼り付け演算子(##)」について、具体的なコード例を交えながら詳しく解説します。 文字列化演算子(#)とは 文字列化演算子「#」は、プリプロセッサで使用される演算子の一つです。マクロ定義内で引数の前に「#」を付けることで、コンパイラに対してそのトークンを文字列リテラルへ変換するよう指示します。 この演算子を活用すれば、通常はダブルクォート()で囲む必要のあるテキストを、クォートなしで文字列として扱うことができます。 サンプルコード #inc
-
C++のstringstreamを使って10進数と16進数を相互変換する方法
C++では、10進数を16進数の文字列に変換したり、その逆に16進数の文字列を10進数に変換したりすることができます。この変換には、C++標準ライブラリが提供するstringstream(文字列ストリーム)機能を利用します。stringstreamは、文字列のフォーマット、解析、数値への変換など、さまざまな用途に活用できる便利なクラスです。また、hexはI/Oマニピュレータの一種で、ストリームへの参照を引数として受け取り、操作後のストリーム参照を返します。10進数から16進数への変換まず、10進数の値を16進数の文字列に変換する例を見てみましょう。抽出演算子「<<」とhexマニピュ
-
C++で文字列リテラル同士を連結するとどうなる?正しい連結方法を解説
C++における文字列と文字列リテラルには、いくつか重要な性質があります。この記事では、C++で2つの文字列を連結する際に覚えておくべきポイントを、具体例とともに解説します。 文字列連結の基本ルール x + y という式で文字列を連結する場合(x と y がどちらも std::string 型)、結果は「x の文字列のコピーの後ろに y の文字列が続いたもの」となります。 x と y のうち、片方だけは文字列リテラルや文字であっても構いません。しかし、両方が文字列リテラルの場合は連結されず、コンパイルエラーになります。 コンパイルエラーになる例 #include<iostream&
-
C++のスタック巻き戻し(スタックアンワインディング)とは?仕組みをサンプルコードで解説
本記事では、C++における「スタック巻き戻し(Stack Unwinding:スタックアンワインディング)」の意味と動作について詳しく解説します。 スタック巻き戻しの基本概念 プログラム内で関数を呼び出すと、その呼び出し元の情報(リターンアドレスなど)がコールスタック上に保存されます。そして、関数から戻るときには、その情報がスタックから取り除かれ(ポップされ)、処理は中断していた箇所から再開されます。 スタック巻き戻しとは、実行時に関数呼び出しスタックのエントリを順次取り除いていくプロセスのことです。このスタック要素の除去には、例外を利用することができます。内部の関数から例外がスローされると、
-
C言語における演算子の優先順位と結合規則の徹底解説
C言語において、演算子の優先順位(operator precedence)は、式中の項がどのようにグループ化されるかを決定し、式がどのような順序で評価されるかを左右します。すべての演算子に同じ優先順位が与えられているわけではなく、たとえば乗算演算子(*)は加算演算子(+)よりも高い優先順位を持ちます。具体例を挙げましょう。x = 7 + 3 * 2;この場合、変数 x に代入されるのは 20 ではなく 13 です。なぜなら、* 演算子の方が + よりも優先順位が高いため、まず 3 * 2 が計算され、その結果 6 に 7 が加算されるからです。演算子の優先順位一覧表以下の表では、優先順位が最も
-
C言語のprintf()で++演算子を使ったときの出力結果を徹底解説
C言語の学習や競技系の試験では、printf() の引数にインクリメント演算子(++)が含まれたコードの「出力結果を求めよ」という問題がよく出題されます。一見シンプルなコードに見えて、実際に出力される数値は直感と異なることが多く、多くの人を悩ませるポイントです。この記事では、典型的な例題を取り上げながら、なぜそのような出力になるのかを順を追って分かりやすく解説します。サンプルコード#include<stdio.h> int main() { volatile int x = 20; pr
-
【C言語】演算子を使わずに2つの数値の合計を求めるプログラム
この記事では、C言語のプログラムにおいて+演算子などの演算子を一切使わずに、2つの数値の合計を求めて出力する方法を解説します。一見すると手強そうな問題ですが、printf()関数の「最小フィールド幅」指定を利用することでエレガントに解決できます。printf()では、書式指定子の * を使うことで、可変引数からフィールド幅(出力する最小文字数)を動的に受け取ることができます。例えば、「Hello」という文字列の前にx個の空白を挿入したい場合は、次のように記述します。サンプルコード#include<stdio.h> main() { i
-
C/C++における三項演算子(?:)とif~else文の違いとは?使い分けのポイントを解説
三項演算子は条件演算子とも呼ばれ、ある条件を判定し、その結果に応じて処理を行うための演算子です。三項演算子を使わなくても、if~else文による条件分岐で同じ処理を実現できます。多くの場合、三項演算子とif~else文の動作結果は同じです。しかし、状況によってはif~else文が使えず、三項演算子を使わなければならないケースが存在します。その代表例が「定数(const)変数への値の代入」です。const修飾された変数には、宣言時に一度だけ値を設定できます。if~else文では宣言後に代入することになるためコンパイルエラーになりますが、三項演算子を使えば宣言と同時に値を初期化できるため、この問題
-
C++の出力ストリーム操作で数値の先頭にゼロを付けて出力する方法
C++で数値を出力する際、先頭にゼロ(先行ゼロ)を付けたいケースはよくあります。しかし、数値の前に直接「0」を並べて書いても、それらのゼロはすべて無視され、実際の数値だけが表示されてしまいます。この問題はC言語ではprintfのフォーマット指定子のオプションで解決できますが、C++ではライブラリを使用することで、出力ストリームを柔軟に操作できます。このライブラリにはsetw()関数があり、直前のテキストと現在のテキストとの間に出力フィールドの幅を確保することができます。さらにsetfill(char)関数を組み合わせれば、その余った領域を任意の文字で埋められるのです。以下のコードでsetw()
-
C++におけるコマンドライン引数の解析方法を徹底解説
C++プログラムは、実行時にコマンドラインから値を受け取ることができます。これらの値はコマンドライン引数(command line arguments)と呼ばれ、プログラムの外部から動作を制御したい場合や、設定値をソースコード内にハードコードせずに柔軟に扱いたい場合に非常に重要な役割を果たします。 コマンドライン引数は、main()関数の引数として処理されます。ここで使われる2つのパラメータの意味は以下のとおりです。 argc:プログラムに渡された引数の総数(プログラム名自身も含まれます) argv[]:渡された各引数へのポインタを保持する配列(argv[0]には通常プログラム名が格納され
-
C++の名前空間(namespace)とは?基本の使い方をわかりやすく解説
この記事では、C++のコードにおいて名前空間(namespace)を使用する方法について、具体例を交えながら詳しく解説します。名前空間が必要な理由まず、身近な例で考えてみましょう。同じクラスに「ザラ」という同じ名前の生徒が2人いたとします。この2人を区別するときには、「住んでいる地域が違う」「母親や父親の名前が違う」など、名前以外の追加情報が必要になりますよね。C++のプログラムでも、まったく同じ状況が発生します。たとえば、あなたが書いたコードの中にxyz()という関数があるとしましょう。ところが、プロジェクトで利用している外部ライブラリにも、まったく同名のxyz()関数が存在していたらどうで
-
C++で円周率(PI)定数を使用する方法
この記事では、C++プログラムで円周率(PI)定数を使用する方法を解説します。PI定数は cmath ヘッダーファイルに含まれており、その定数名は M_PI です。ヘッダーファイルをインクルードするだけで、特別な定義を行うことなくすぐに利用できます。M_PI は double 型の定数として定義されており、値は約3.14159265358979です。なお、M_PI は標準C言語では厳密には規格外のため、コンパイラによっては使用できない場合があります。その場合は、_USE_MATH_DEFINES を定義するか、自前で定数を定義する必要があります。サンプルコード次の例では、PI定数を使用して円の
-
C++でmain()関数を再帰的に呼び出すことは合法なのか?
はじめにC言語やC++において、main関数は他の関数と本質的に同じ性質を持っています。そのため、通常の関数で使用できる機能の多くは、main関数の中でも同じように利用できます。そして実際のところ、C++ではmain()関数を再帰的に呼び出すことは標準規格上も合法です。ただし、main関数はオーバーロードしたり、そのアドレスを取得したりすることはできないという制限がある点には注意が必要です。以下のプログラムでは、main()を再帰的に呼び出すことで、数値を降順(逆順)に出力する例を紹介します。サンプルコード#include <iostream>using namespace std
-
C++で乱数を生成する方法をわかりやすく解説
C++で乱数を生成する方法を紹介します。ここでは、0から指定した最大値までの範囲で乱数を生成します(このプログラムでは最大値を100としています)。 乱数を生成する際に使用するのが srand() 関数です。この関数はC標準ライブラリに含まれており、void srand(unsigned int seed) という形式で、rand関数が使用する乱数生成器にシード(種)を設定します。 srand()関数の宣言 void srand(unsigned int seed) srand()関数は seed というパラメータを1つ受け取ります。これは、疑似乱数生成アルゴリズムのシードとして使用される整数