サイゼリヤといえばイタリア料理のファミレスであり、リーズナブルな価格で食べられるということで人気が高いです。先日、サイゼリヤのグランドメニューから1000円以下の組み合わせをランダムに表示するWebアプリが話題となりました。
サイゼリヤ1000円ガチャをつくってみた(Sho Maruyama 氏)
https://qiita.com/marusho_summers/items/a2d3681fac863734ec8a
そして、このガチャを見たプログラマが「サイゼリヤで1000円あれば最大何kcal摂れるのか」という記事を書いたのをきっかけに、「サイゼリヤ大喜利」に発展していきました。
「サイゼリヤで1000円あれば最大何kcal摂れるのか」を量子アニーリング計算(Wildqat)で解いてみた。(穂高 久保 氏)
https://qiita.com/hodaka0714/items/cf44b4ece992a39b5be4
サイゼリヤのお客さんにとっては、この上なくどうでもよい議論かもしれませんが、プログラミングの問題としては非常に興味深い問題であり、解説しているサイトを見るといろんな解き方があるんだなぁと感心してしまいます。
- 「サイゼリヤで1000円あれば最大何kcal摂れるのか」をSMTソルバー(Z3)で解いてみた。
- 「サイゼリヤで1000円あれば最大何kcal摂れるのか」を整数計画法ソルバー(PuLP)で解いてみた。
- 「サイゼリヤで1000円あれば最大何kcal摂れるのか」をTeX言語で計算する ~TeX言語で動的計画法(DP)~
- 「サイゼリヤで1000円あれば最大何kcal摂れるのか」をマルコフ連鎖モンテカルロで解いてみた。
- 「サイゼリヤで1000円あれば最大何kcal摂れるのか」をExcel のソルバーでで解いてみた。
- 「サイゼリヤで1000円あれば最大何kcal摂れるのか」をなでしこでDPで解いてみた。
しかし、よく考えてみると、サイゼリヤのグランドメニューのなかでカロリー表示があるものは、たったの100種類程度であり、Excel関数で解こうと思えばギリギリ解ける範囲ではないかと思われます。そこで、Excelを使って、しかもマクロやアドインを使わずに「サイゼリヤのメニュー1000円以内でカロリーが最大になる注文」を求めてみましょう。
問題
サイゼリヤのグランドメニュー(ランチ除く)で、税込合計1000円以下となるように注文した場合、摂取できるカロリー(kcal)の最大値とその組み合わせを求めなさい。また、カロリー上位10位の組み合わせを求めなさい。ただし、メニューは2019/5/19現在のものを使用し、ドリンクやバージンオイルなどカロリー表示が無いものを除く。
目次
特別企画なので動画はありません。
- 1.メニューを入力する
- 2.メニューを1つだけ注文する場合
- 3.重複無しで2つ注文する場合
- 4.重複無しで3つ注文する場合
- 5.重複無しで4つ以上注文する場合
- 6.実際のサイゼリヤの店舗で1940kcalを摂取してみた
- 7.重複ありの場合
- 8.Excelとサイゼリヤ
- 9.追記:ジョイフルガチャ
解説
1.メニューを入力する
Excelにメニュー、カロリー(kcal)と税込価格(円)を入力します。最新のメニューはサイゼリヤの公式サイトで確認できますので、これを見ながら手入力をします。時期によってメニューの数は変わると思いますが、執筆時点で98種類です。
ここで、E列に1円あたりのカロリー(kcal/yen)を求めます。この値を、Kiro calorie Per Yen を略して「KPY」と呼ぶことにします。
- セルE2:=C2/D2
KPYの降順で並べ替えることによって、少ない金額でより多くのカロリーが摂取できるメニューが分かります。左端に1列挿入して、1~98の連番(注文番号)を振っておきます。また、表全体(A1:F99)に「メニュー」という名前を定義しておきます。
ちなみに、税込価格の最小値は半熟卵のトッピング69円なので、合計注文金額が932円以上になったら追加の注文はできません。
2.メニューを1つだけ注文する場合
メニューの中で最もカロリーが高いのは「カルボナーラWサイズ」1730kcalです。ベスト10を抽出すると、第10位は「アーリオ・オーリオWサイズ」1120kcalです。最終的にベスト10の組み合わせを求めるということは、このベスト10の組み合わせは必ず1000円以内で1120kcal以上になっているはずです。つまり、KPYは1.12以上です。
98種類のメニューのうちKPYが1.12以上のものを抽出したら53種類ありました。
3.重複無しで2つ注文する場合
まず、同じメニューを2つ頼んではいけないという縛りで考えてみましょう(重複ありの場合については後述)。
複数注文するときのルールですが、注文番号をA列、B列、C列、D列、・・・と並べていきますが、必ず注文番号の小さいほうから順(A<B<C<D<・・・)、つまり、KPYが高いほうから順に並べることにします。これによって、注文すればするほど合計のKPYが下がることになります。
新規シートのセル範囲A2:A54に1~53の連番を入力します。B2:B54に2を入力します。
A55、B55にそれぞれ次の数式を入力して、A56:B5142にコピーします。なお、コピーしたら値の貼り付けで数式を消します。
- A55:=A2
- B55:=B2+1
これによって、1~53と2~98の総当たりの組み合わせを出力することができます(53x97=5141通り)。さらに、C列に次の数式を入力し、B列からA列を引きます。
- C2:=B2-A2
フィルタで0以下のものを抽出して、行削除をするとプラスの数だけが残り、A列<B列となります。これで、2つの注文番号の重複しない組み合わせが求められます(3763通り)。
なぜ、A列を1~53にしたのかというと、54番以降のメニューはKPYが1.12未満なので、54番以降のメニューを2つ注文してもKPYが1.12以上にはならない(ベスト10に入らない)からです。
VLOOKUP関数またはINDEX関数等を用いて、A列、B列の注文番号を検索値として、カロリーと税込価格を求めます。また、2つのメニューのカロリーと税込価格の合計を求めます。さらにKPYも求めます。
- D2:=VLOOKUP(A2,メニュー,4,0)
- E2:=VLOOKUP(A2,メニュー,5,0)
- F2:=VLOOKUP(B2,メニュー,4,0)
- G2:=VLOOKUP(B2,メニュー,5,0)
- H2:=D2+F2
- I2:=E2+G2
- J2:=H2/I2
I列で合計金額1000円以下を抽出します(2794件)。このなかで合計カロリーが多いもの10件を抽出します。
1つだけ注文した場合と、2つ注文した場合の上位10位をまとめると次のようになります。順位を求めると第10位(同率)のカロリーは1730kcalです。したがって、3個以上の注文をした場合も含めて、最終的にベスト10の組み合わせを求める場合、その組み合わせは必ず1000円以内で1730kcal以上、KPYは1.73以上となります。
4.重複無しで3つ注文する場合
1000円未満でJ列1.73未満を抽出します(2692件)。現時点で、2つの注文のKPYが1.73未満になっているということは、少なくともB列の注文は1.73未満であり、追加注文するメニューはさらにKPYが少ないので、追加注文によって1.73以上になることは計算上ありえません。したがって、これらの行はすべて削除してもよいということになります。
行削除します(削除フラグでもよい)。さらに、前述のとおり合計が932円以上になったら追加の注文はできないので、合計(H列)で931円以下に絞ると83件のレコードしか残りません。これらのレコードを別のシートに移して、3つ目の注文を考えましょう。
C列に3個目の注文番号を入れたいと思います。とりあえずC2:C84に3と入力しておきます。
A85~H85にそれぞれ次の数式を入力して、A86:H7969にコピーします。なお、コピーしたら値の貼り付けで数式を消してください。
- A85:=A2
- B85:=B2
- C85:=C2+1
- E85:=E2
- F85:=F2
- G85:=G2
- H85:=H2
これによって、A-B列の組み合わせ83通りと3~98の総当たりの組み合わせを出力することができます(83x96=7968通り)。
さらに、D列に次の数式を入力し、C列からB列を引きます。
- D2:=C2-B2
フィルタで0以下のものを抽出して、行削除をするとプラスの数だけが残り、B列<C列となります。これで、3つの注文番号の重複しない組み合わせが求められます(6642通り)。
VLOOKUP関数またはINDEX関数等を用いて、C列の注文番号を検索値として、カロリーと税込価格を求めます。また、3つのメニューのカロリーと税込価格の合計を求めます。さらにKPYも求めます。
- I2:=VLOOKUP(C2,メニュー,4,0)
- J2:=VLOOKUP(C2,メニュー,5,0)
- K2:=E2+G2+I2
- L2:=F2+H2+J2
- M2:=K2/L2
H列で合計金額1000円以下を抽出します(3307件)。このなかで合計カロリーが多いもの10件を抽出します。
1つ~3つ注文した場合をまとめると次のようになります。順位を求めると第9位(同率)のカロリーは1820kcalです。したがって、4個以上の注文をした場合も含めて、最終的にベスト10の組み合わせを求める場合、その組み合わせは必ず1000円以内で1820kcal以上、KPYは1.82以上となります。
5.重複無しで4つ以上注文する場合
4つ以上の注文も同じ抽出作業をしていきます。M列1.82未満を抽出します(3211件)。これらの行はすべて削除します。
合計(K列)で931円以下に絞ります。そして、さきほどと同様の作業を繰り返し、4つ、5つと増やしていきます。
順位を求めると第10位のカロリーは1831kcalです。
5つ注文した場合の最大値は1808kcalです。注文個数が増えると合計金額が増えますが、KPYが減るのでどんどんレコード件数が減っていきます。注文個数が6つになるとすべての1000円以下の組み合わせで、合計カロリーが1831kcal以下、KPYも1.831より小さくなるため、6点以上の注文を考える必要はありません(カロリー上位10位の変動がない)。
よって、すべての組み合わせを計算した結果、ベスト10は次の通りとなり、計算上の最大カロリー摂取量は1940kcalとなります。
6.実際のサイゼリヤの店舗で1940kcalを摂取してみた
しかし、この問題は、Excelで答えが出たら終わりではありません!!
実際の店舗で注文して完食できることを確認して、フィニッシュとなります。大量のメニューを注文して食べ残したり、複数人で分担して食べたら「最大カロリー摂取量」にならないからです。
というわけで、サイゼリヤに行って食べてきました。ようこそ、炭水化物の夢の国へ。
- ラージライス 219円、454kcal
- アーリオ・オーリオ(Wサイズ) 574円、1120kcal
- ポテトのグリル 199円、366kcal
そして、ある事に気が付いてしまいました。メニューに小さい字で書いてあるケチャップ12kcal。
店員さんがにこやかに持ってきてくれたカゴメのトマトケチャップ。完全に見落としており、計算に入れていませんでした。
しかし、ケチャップをかけることが選択的であり、備え付けの調味料と同じ扱いであることなどを総合的に勘案して、今回はノー・ケチャップとさせていただきます!!
パスタの2人前が何のトッピングもなく、ケチャップも無く、塩味のポテトと大盛ご飯が混ざり合って、食べた人でなければ分からない絶妙な気持ち悪さと後味の悪さを感じました。何とか完食しましたが、最後のほうは、おいしい水で流し込む食べ方になりました。
支払金額1000円、おつり8円です。間違いなく1940kcalが最大値であることが確認できました。・・・(答)
7.重複ありの場合
注文番号をA列<B列<C列<D列<・・・とすると重複の無い組み合わせを求めることができますが、A列 <= B列 <= C列 <= D列 <=・・・とすれば重複を許す組み合わせになります(列の差をとって0以下を抽出するところを、0未満にすればよい)。
つまり、同じものを何個も注文してもよいというルールになります。計算の方法は同じです。そして、以下が、上位の5つとなります。ほとんどライスです。ご覧のように、現実的に注文できる内容ではない(実際に店舗で注文する勇気が無かった・・・)ので、これはカロリー最大摂取量の解として不適切です。
8.Excelとサイゼリヤ
Excelで100種類の商品を組み合わせるのに8000行x25列くらい使って計算しました。そして、サイゼリヤの店内に滞在することのできる時間で計算可能です。途中で30秒くらい画面がフリーズしたりすることはありますが、ギリギリ解けます。
この点について、ExcelよりPythonのほうが優れているとか、めんどくさいとか、まだExcelで消耗してるの?などと言うのは的はずれです。マクロすら習得するのが難しい一般の人たちが、サイゼリヤの滞在時間内にプログラミングを覚えて答えが出せるのでしょうか?プログラミング言語はハードルが高く、その習得時間や応用のし易さなどを計算に入れると、Excelのほうが圧倒的に優れていることは言うまでもありません。
Excelは、庶民にも親しみやすく手軽に利用できること、一般的に普及していることなど、サイゼリヤと共通する部分があるのです。
9.追記:ジョイフルガチャ
サイゼリヤに続き、ジョイフル1000円ガチャも登場。
君たちは500円で定食が食べられるジョイフルを知っているか!?便乗してジョイフル1000円ガチャを作ってみた。
https://note.mu/418iamteapot/n/n8a5a1fcb9f83
というわけで、2019/5/21現在、ジョイフルのグランドメニュー1000円以内で摂れるカロリーの最大値も計算しました。ライスとポテトに、1.5倍増量キャンペーン中のごぼうという組み合わせです。
- ごぼう唐揚げ 744kcal、214円
- セットライス 330kcal、106円
- ライスおかわり 330kcal、106円
- 大盛りポテトフライ(360g) 841kcal、322円
- ポテトフライ(180g) 421kcal、214円
962円で、合計カロリー2666kcal。