ニート歴10年からの数学日記

2008年〜2009年の高一の冬休みから無職。最長で4ヶ月ほどの中断アリ。

ジュニア算数オリンピック 三次元配列の問題 その1

【随時更新】解答に必要な機能まとめ - ニート歴10年からの数学日記【随時更新】計算量の減らし方まとめ - ニート歴10年からの数学日記を使って、ジュニア算数オリンピックの三次元配列の問題について考察していく。
 

 

97年度ファイナル問題 問題4

『6つの面が異なる色でぬり分けられた立方体が1個あり、その各面に小さなシールを少なくとも1枚ははりつけます。
この立方体を、置く面や向きを変えて、さまざまな角度から写真にとりました。

(問い1)写真を現像して、写っている面の色の種類が異なるものをすべて選び出しました。
何枚の写真を選び出しましたか。もっとも多い場合を答えなさい。

例えば、図のような2枚の写真では、写っている面の色の種類が異なります。
(2つの面が写っている写真) (3つの面が写っている写真)

(問い2)(問い1)で選び出した写真を見ると、写っているシールの枚数もすべて異なっていました。
立方体にはりつけたシールは全部で何枚でしょうか。もっとも少ない場合を答えなさい。

例えば、図のように2枚、3枚、4枚のシールがはってある3つの面が写った写真の場合、写っているシールの枚数は9枚となります。
(3つの面が写っていて、2枚4枚3枚)』

table := [    #これは正直グラフの問題だったかもしれん。サイコロみたいに考えることにした
    [1, 2, 3, 4],
    [0, 2, 3, 5],
    [0, 1, 4, 5],
    [0, 1, 4, 5],
    [0, 2, 3, 5],
    [1, 2, 3, 4]
];

side1 := ?1;
side2 := table[?1][?2];

side1[?3] == side2[?4];
side3 := side1[?3];

いきなり自然言語が入るようだが、ここでside1とside2で、位置が入れ替わっただけのものは消去したい。数学の組み合わせでもPとかCとかで似たような概念があったと思うが、あんな感じで。side1だけ多くなりそうな気もするが、1つの選択肢が消えたら、side1も1つ消えるはずだから、成立するのではないか。

two_side_result := every.side2.数;

side1とside2とside3の間でも同じ処理をする;

three_side_ result := every.side3.数;

print(6 + two_side_result + three_side_result);

n_list := [A, B, C, D, E, F];

every_2side_sum := every(side1, side2).(n_list[side1] + n_list[side2]);
every_3side_sum := every(side1, side2, side3).(n_list[side1] + n_list[side2] + n_list[side3]);

([1, 2, 3, 4, 5, 6] + every_2side_sum + every_3side_sum) ~ not_equal();    #python風に+でリストの連結を表す

n_list.sum()を最小化するように設定;

print(n_list.sum());


ちょっと大丈夫なのかという気もするけど。あとから1面もあることに気付いて足した。

問い1の答えは、この記述を手計算すれば出る。26通り。


問題は問い2で、分からないので答えを見た。
1つの面に着目すると、写真の写り方は1面が1通り、2面が4通り、3面が4通りある。つまり写真に写った値の総和を9で割れば、それぞれの面で1回ずつになって、各面の合計が出る。
26通りの最善を考えると、1~26で、足し合わせると(1+26)*(26/2)になる。それを9で割ると、39。それで少なくとも39枚はシールが必要だと分かる。
1の裏に2、3の裏に6、9の裏に18で、その条件を満たすサイコロができるらしい。

最善から考えて、全体を利用して、各面の全体を出す。そこまでができていなかった。本質的には制約から制約を弾き出すということだと思うんだが。
最後は解答でも結果だけがドンと出てくる感じで、でも一応法則性があるようにも見える。
 

98年度トライアル問題 問題8

『すべての面が白色か黒色である一辺1cmの立方体ブロックがたくさんあります。これらのうちの27個を使って、1辺3cmで、すべての面が黒色ブロックが2個ずつ同じもようになる立方体を作りたいと思います。
(例)の立方体は、どの面も同じもようになっています。又、この時、黒色ブロックは8個使っても9個使ってもこの立方体を作ることができます。
(例)のほかにも、いろいろなもようの立方体をつくることができます。このようにしてできる立方体について、次の問いに答えなさい。
ただし、回転させたり、うら返したりして重なるものはすべて同じもようとします。

(例)
上の面

左の面

(問い1)次のもようのうちで、実際に作ることができる立方体の面のもようはどれでしょうか。その番号をすべてあげなさい。

(問い2)問い1、で作ることができる立方体がそれぞれ何個の黒色ブロックを使っているかを考え、最も多く使う場合と最も少なく使う場合の個数を答えなさい。』

table := [~2][~2][~2];

table[?][?][?] := カブり無しで全てに : ? : カブり有り := ["白", "黒"].every;

side := [~2][~2];

side[?][?] := カブり無しで全てに : ? : カブり無し := ["黒" * 2 + "白" * 7].every;    #普通に考えたら["黒"] * 2なんだが

def table_turn_equal(table1, table2) {
    y_len := len(table1);

    alt_2 := [
        list(map(lambda y: table2[y][0], range(y_len))),
        list(map(lambda y: table2[y][1], range(y_len))),
        list(map(lambda y: table2[y][2], range(y_len))),
        list(map(lambda y: table2[y][3], range(y_len)))
    ];

    or(1) {
        table1 == table2;
    } or {
        table1 == list(map(lambda y: table2[y].reverse, range(y_len)));
    } or {
        table1 == table2.reverse;
    } or {
        table1 == list(map(lambda y: table2[y].reverse, range(y_len))).reverse;
    } or {
        table1 == alt_2;
    } or {
        table1 == list(map(lambda y: alt_2[y].reverse, range(y_len)));
    } or {
        table1 == alt_2.reverse;
    } or {
        table1 == list(map(lambda y: alt_2[y].reverse, range(y_len))).reverse;
    }
}

table_turn_equal(table[0], side);
table_turn_equal(table[2], side);
table_turn_equal(table[?][0], side);
table_turn_equal(table[?][2], side);
table_turn_equal([table[?][0][0], table[?][1][0], table[?][2][0]], side);    #これで良いのか?
table_turn_equal([table[?][0][2], table[?][1][2], table[?][2][2]], side);

result := table.every.(it == "黒").数;

記録1;

resultを最大化するように設定;

print(result);

記録1~;

resultを最小化するように設定;

print(result);


答えは、ルールに則って展開していったら、1と2と7が違うんじゃないか。
個数は、真ん中にあるものを*6、辺にあるものを*6/2で*3、角にあるものを*6/3で*2。
 

99年度トライアル問題 問題12

『白色と赤色の同じ大きさの小さな立方体がたくさんあります。これらの小さな立法体をいくつか使って大きな立方体を作ると、大きな立方体の対角線(図のAG、BH、CE、DFの直線)上の小さな立方体はすべて赤色でその他はすべて白色でした。赤色の小さな立方体の数が17個のとき、白色の小さな立方体の数はいくつありますか。

(図は省略 大きな立方体は、上がABCDで、それに対応するようにEFGH)』

table := [~?1][~?2];

table := カブり無しで全部に : ? : カブり有り := "白";

for(i in range(A)) {
    table[i][i] := 置き換え := "赤";
    table[i][A - i - 1] := 置き換え := "赤";
    table[A - i - 1][i] := 置き換え := "赤";
    table[A - i - 1][A - i - 1] := 置き換え := "赤";
}

table[?][?].(it == "赤").数 == 17;

print(table[?][?].(it == "白").数);


答えを考えると、中心から8つ足が角に向けて伸びていて、奇数だったら真ん中に1つある。
17は1と8*2なので、5*5*5の立方体で、=125。そこから-17で、答えは108だろう。
 

00年度トライアル問題 問題11

『6つの面がすべて赤色の大きな直方体が1つあります。
今、この直方体を、形も大きさもすべて同じ小さな直方体の積み木に切り分けバラバラにしたあと、1つ1つの積み木の面の色をしらべてみました。
すると、最高でも3つの面が赤色で4つ以上の面が赤色の積み木はなく、2つの面が赤色の積み木は12個ありました。
つぎに、バラバラにした積み木のうちのいくつかをつかって、はじめの大きな直方体とは異なる別の直方体を新しく作りました。新しく作った直方体も6つの面はすべて赤色です。
さて、この新しく作られた直方体は、最も多くていくつの積み木で作られていますか。』

table := [~A][~B][~C];    #pythonで多次元配列の初期化ってどうやるんだろう

table := カブり無しで全部に : ? : カブり有り := 0;

every(X, Z) {
    table[0][X][Z] := table[0][X][Z] + 1;
    table[A - 1][X][Z] := table[A - 1][X][Z] + 1;
}
every(Y, Z) {
    table[Y][0][Z] := table[Y][0][Z] + 1;
    table[Y][B - 1][Z] := table[Y][B - 1][Z] + 1;
}
every(Y, X) {
    table[Y][X][0] := table[Y][X][0] + 1;
    table[Y][X][C - 1] := table[Y][X][C - 1] + 1;
}

table[?][?][?].(it == 2).数 == 12;
table[?][?][?] ∌ 4;

ゴミ箱 :=  : (D - 2) * (E - 2) + (D - 2) * (F - 2) + (E - 2) * (F - 2) : 除去 := table[?][?][?].(it == 1);
ゴミ箱 :=  : (D - 2) * 4 + (E - 2) * 4 + (F - 2) * 4 : 除去 := table[?][?][?].(it == 2);

(D * E * F)を最大化するように設定;

print(D * E * F);


4面以上赤いのを含まないということで、最初の直方体は、どの辺も2以上だと分かる。どこかの辺を伸ばすたびに2つの面を持つ12個の内の4個が消費されるので、2*2*2から3しか伸ばせない。
最初の直方体は、2*2*5か、2*3*4か、3*3*3。次の直方体で使えるのが一番多いのは、何にしても3*3*3。
4つの面を持つのが無いので、次の直方体も2*2*2からスタートする。2*2*5=20で、2*3*4=24なので、一つ下のグレードの2*3*4=24が良いのではないか。いやしかし小さいのも直方体だという話だけど、可能なのかな。よく分からない。


答えを見ると、真四角の四角柱なら可能とのこと。俵みたいに積み重ねたのを、別の形で積み重ねる。
ただ、先に書かれているのは、そのままスケールダウンした18個で、最初は四角柱は含まないという想定だったのかもしれない。どちらも正解とのことだ。