計算の仕組み・技術情報

当サイトは、JR線の利用において移動コストを最小化する「最安分割きっぷ」と、それを実現する経路を自動的に導出するシステムです。ここでは、なぜきっぷを分割すると安くなるのかという仕組みと、当サイトを支える情報工学に基づいた計算アルゴリズムについて解説します。また、どのように運営されているかの技術情報も説明します。

1. なぜきっぷを分割すると安くなるのか?

JRの運賃は原則として乗車する営業キロの合計に基づいて算出されますが、以下の5つの要因により、途中の駅で乗車券を分割して購入した方が合計運賃が安価になるケースが存在します。

① キロ単価の非単調性

運賃のキロ単価は一定ではなく、距離帯によって変動するため、分割した方が安価となる場合があります。

【例:横浜駅〜東京駅(東海道本線)の場合】

  • 通しで購入: 営業キロ28.8kmは「26km~30km」の運賃帯(28kmとして計算)となり、消費税や端数処理を経て530円となります。
  • 蒲田駅で分割: 横浜〜蒲田(14.4km)、蒲田〜東京(14.4km)はそれぞれ「10km~15km」の運賃帯(13kmとして計算)となり、260円×2枚で520円となります。

結果として、分割するだけで10円安くなります。

530円(28.8km)260円(14.4km)260円(14.4km)横浜蒲田東京

② 特定区間運賃の利用

私鉄などと競合する区間には、通常の距離制運賃よりも安い「特定運賃」が設定されていることがあり、その区間を独立させて分割することで全体が安くなります。

【例:横浜駅〜池袋駅(東海道本線・山手線)の場合】

  • 通しで購入: 営業キロ37.4kmに対する通常計算で720円となります。
  • 渋谷駅で分割: 営業キロ29.2kmに対する運賃は530円ですが、渋谷〜横浜間には東急東横線に対抗するための「特定運賃」が設定されており、特例として440円となります。池袋〜渋谷間は通常の計算による210円です。

これらを合計すると650円となり、特定運賃の恩恵を受けることで通しで買うよりも安くなります。

720円(37.4km)440円(29.2km)210円(8.2km)横浜渋谷池袋

③ 長距離区間における距離帯間隔の拡大

これは①とよく似ています。営業キロが長くなるにつれて運賃が上昇する間隔が広がるため(例:50kmまでは5kmごと、101km〜600kmは20kmごと)、短距離の乗車券を別途購入して長距離側の営業キロを調整することで、全体を低減できる場合があります。

【例:福山駅〜静岡駅(山陽本線・東海道本線)の場合】

  • 通しで購入: 営業キロ611.0kmは「601km~640km」の運賃帯(620kmとして計算)となり9,790円となります。
  • 焼津駅で分割: 営業キロ597.5kmは「581km~600km」の運賃帯(590kmとして計算)となり、9,460円となります。焼津から静岡は13.5kmで240円です。1.5km分は無駄になりますが、先述の7.5km分の運賃削減効果(通し運賃の620km帯から590km帯への引き下げによる差額)が上回るため、全体として安くなります。

これらを合計すると9,700円となり、営業キロの幅を小さく調整することで通しで買うよりも安くなります。

9,790円(611.0km)9,460円(597.5km)240円(13.5km)福山焼津静岡

④ 電車特定区間運賃の適用

割安な「電車特定区間」と通常の「幹線」をまたがって乗車する場合、全区間が割高な幹線の賃率で計算されてしまうため、境界付近で分割して電車特定区間を独立させます。

【例:久宝寺駅〜大河原駅(関西本線)の場合】

  • 通しで購入: 営業キロ55.5kmは「51km~60km」の運賃帯で幹線の賃率として計算され、消費税や端数処理を経て990円となります。
  • 法隆寺駅と木津駅で分割: 3つの分割区間の営業キロはそれぞれ「16km~20km」の運賃帯(18kmとして計算)となり、幹線運賃のままだとそれぞれ330円となります。しかし、法隆寺駅で分割することにより久宝寺駅~法隆寺駅間が電車特定区間内完結で320円となり、合計は980円となります。

結果として、分割すると10円安くなります。

電車特定区間内990円(55.5km)320円(18.6km)330円(18.8km)330円(18.1km)久宝寺法隆寺木津大河原

⑤ 特定都区市内制度の適用または回避

分割することにより、特定都区市内の特例制度を利用して運賃計算経路を短縮したり、逆に特例の適用を避けるために境界駅で分割することで安くなることがあります。

【例:宮島口駅〜網干駅(山陽本線)の場合】

  • 通しで購入: 営業キロ261.1kmは「261km~280km」の運賃帯で4,840円となります。
  • 五日市駅で分割: 五日市駅は広島市内にあるので、五日市〜網干(251.7km)は、「広島市内→網干」として中心駅の広島駅からの運賃計算です。広島~網干(239.6km)は「221~240km」の運賃帯(230kmとして計算)となり、4,070円となります。

結果として、分割するだけで250円安くなります。

広島市内4,840円(261.1km)中心駅200円(9.7km)4,070円(239.6km)宮島口五日市広島網干

2. 当サイトの探索アルゴリズムと技術的優位性

既存の分割乗車券プログラムの多くは、利用者が事前に「乗車する経路」を指定する必要がありました。また、計算速度を優先した単純な動的計画法(DP)では、最適化の過程で同額となる別の分割パターンが枝刈りされてしまい、出力される解が一つに限定されるという課題がありました。

当システムでは、情報工学におけるグラフ理論と最新のWeb技術を応用し、以下の独自アプローチを採用しています。

経路指定不要の自動探索

K-最短経路アルゴリズム(Yen's Algorithm)を応用することで、利用者が自ら経路を指定することなく、分割乗車券によって安価となる「迂回経路」も含めた候補ルートの列挙を自動で行います。

ヒューリスティック探索の不採用

A* アルゴリズムなどは高速ですが、JRには「営業キロが物理的な距離よりも短く設定されている区間」が存在します。物理的距離を推定値に用いるとコストを過大評価し最安解を見逃すリスクがあるため、解の正当性を完全に保証する手法を採用しています。

同額パターンの完全列挙

現実の鉄道利用では、分割位置による途中下車の可否など利便性を左右する要因があります。当システムは1次元DPの最適化過程で枝刈りを行わず、同額となる複数の最安分割パターンを完全に列挙し、実用上の選択肢を全て提示します。

多層キャッシュによる高速化

複雑な計算アルゴリズムによるサーバー負荷を軽減するため、Cloud RunとFirebase Firestoreを連携。一度計算された解は非同期でデータベースにキャッシュされ、2回目以降の同一検索に対しては数ミリ秒での即時応答を実現しています。

3. 運賃の「逆転現象」への対応

特定の条件下では、乗車経路を外方へ延伸することで運賃が安くなる「逆転現象」が発生します。例えば、特定都区市内制度において、あえて目的地の先の駅まで切符を買うことで、発駅が都区市内中心駅からの計算に切り替わり、結果的に運賃が安くなる現象などです。

当システムでは、こうした複雑な運賃規則(経路特定区間や特定都区市内など)をアルゴリズムの内部に組み込み、限界距離を算出した上での枝刈りを行うことで、延伸による逆転現象も考慮した「真の最安運賃」を導出する処理を行っています。

ただし、区間変更を用いて運賃を安くする方法については採用していません。

4. 技術情報

当サイトは、高度なアルゴリズムの実行とレスポンスの高速化を両立するため、現代的なWeb技術スタックとクラウドインフラを組み合わせて構築されています。

技術スタック

領域技術・ツール採用の目的・意図
FrontendNext.js (App Router), TypeScriptサーバーサイドレンダリング(SSR)による初期表示の高速化と、複雑な運賃ドメインモデルの型安全性担保。
StylingTailwind CSS一貫性のあるモダンなUIデザインの迅速な実装と、クリーンなスタイル管理。
Backend / APINext.js Route Handlersフロントエンドと同一リポジトリ(モノレポ)で型定義やユーティリティを共有し、開発効率を最大化。
DatabaseFirebase Firestore計算コストの高い経路探索結果をキャッシュし、2回目以降の同一検索を数ミリ秒で即時応答。
InfrastructureGoogle Cloud Runステートレスなコンテナによる安定稼働と、アクセス状況に応じた柔軟なオートスケーリング。
Object StorageCloudflare R2経路探索に使用するグラフデータ(`graph_data.bin`)やWasmモジュール(`split_pass.wasm`)を低レイテンシかつデータ転送(エグレス)手数料無料で高速配信。
CI/CD / DevSecOpsGitHub Actions, Vitest, Takumi Guard, Cloud Build自動テスト・Strict Lintの実施、npmパッケージのサプライチェーン攻撃対策、およびブランチごとのプレビュー環境自動生成。

システムの工夫と最適化

① 浮動小数点数演算エラーの完全排除

JavaScriptで小数の計算を行うと、IEEE 754規格に起因する丸め誤差が発生します。JRの営業キロは「小数第1位」まで定義されているというドメイン特性を考慮し、計算前にすべてのキロ数を10倍して「整数」として扱い、最終的な出力時のみ10で割るゼロ依存のアーキテクチャを採用しています。これにより、計算精度と処理速度を極限まで両立させています。

② ノンブロッキングな Fire-and-Forget キャッシュ

新規経路探索時の計算結果をFirestoreへキャッシュ保存する際、クライアントへのレスポンス返却処理をブロックすることなく(`await`せずに)バックグラウンドで非同期書き込みを実行します。キャッシュ書き込みの遅延がユーザー体験の低下に直結しないノンブロッキング設計にしています。

③ 安全かつ低コストなCI/CD運用

GitHub Rulesetによるメインブランチ保護と自動テスト、サプライチェーン攻撃を防ぐセキュリティスキャン(Takumi Guard)を統合。また、モックデータのGitHubへのキャッシュによるGCS費用削減(FinOps)や、プルリクエストごとに Cloud Run のタグ付きデプロイを用いて動的に検証用プレビューURLを発行する体制を整えています。

④ WasmとグラフデータのR2配信による高速化とコスト最適化

運賃計算をユーザーの端末で計算させるためにWebAssemblyを採用しています。Wasmモジュール(`split_pass.wasm`)および運賃計算に必要なグラフデータ(`graph_data.bin`)は、配信にかかるデータ転送量手数料が発生しない Cloudflare R2 から配信しています。これにより、インフラコストを最小限に抑えつつ、ユーザーへのロード時間を大幅に短縮しています。