「9枚の白紙カード」 ~ 解答・解説編
まずは、「9枚の白紙カード」の問題本体ではなく、ヒントとして出した1~9のカードを三分配して、三竦み(さんすくみ)になる分け方について考えてみましょう。
9枚のカードを三枚ずつ三つに分ける方法は、
$${{}_9C_3 × {}_6C_3 ÷ 3! = \dfrac{9!}{6! 3!} × \dfrac{6!}{3! 3!} ÷ 3! = \dfrac{9!}{(3!)^4} = 280}$$ (通り)
あります。手で調べるのには、骨が折れそうな数ですが、280通りの中には、{1,2,3}vs{4,5,6}vs{7,8,9}の様に、明らかに「戦力差」があるような分け方も含まれており、三竦み状態を探す上では無駄です。
そこで、候補を絞るため、合計が同じになるような分配だけをピックアップしてみましょう。
1~9までの合計は45なので、15づつです。
「和が15になるような相異なる3つの自然数」を列挙すると、
{1,5,9},{1,6,8},{2,4,9},{2,5,8},{2,6,7},{3,4,8},{3,5,7},{4, 5, 6}
の8通りしかありません。
そしてこの中から、重複がなく、三竦みになるような三組の選び方を探すために、まず、重複がないような三組を選ぶと、
{1,5,9} vs {2,6,7} vs {3,4,8}
{1,6,8} vs {2,4,9} vs {3,5,7}
だけが見つかります。果たして、三竦み状態になっているかとチェックしてみると、なんと両方とも三竦み状態です。
前者について確かめてみましょう。
A={1,5,9},B={2,6,7},C={3,4,8}とします。
a=(1,5,9) , b=(2,6,7) → 1<2 , 5<6 , 9>7 → b が勝ち
a=(1,5,9) , b=(2,7,6) → 1<2 , 5<7 , 9>6 → b が勝ち
a=(1,5,9) , b=(6,2,7) → 1<6 , 5>2 , 9>7 → a が勝ち
a=(1,5,9) , b=(6,7,2) → 1<6 , 5<7 , 9>2 → b が勝ち
a=(1,5,9) , b=(7,2,6) → 1<7 , 5>2 , 9>6 → a が勝ち
a=(1,5,9) , b=(7,6,2) → 1<7 , 5<6 , 9>2 → b が勝ち
b=(2,6,7) , c=(3,4,8) → 2<3 , 6>4 , 7<8 → c が勝ち (以下一部省略)
b=(2,6,7) , c=(3,8,4) → c が勝ち
b=(2,6,7) , c=(4,3,8) → c が勝ち
b=(2,6,7) , c=(4,8,3) → c が勝ち
b=(2,6,7) , c=(8,3,4) → b が勝ち
b=(2,6,7) , c=(8,4,3) → b が勝ち
c=(3,4,8) , a=(1,5,9) → a が勝ち
c=(3,4,8) , a=(1,9,5) → c が勝ち
c=(3,4,8) , a=(5,1,9) → a が勝ち
c=(3,4,8) , a=(5,9,1) → a が勝ち
c=(3,4,8) , a=(9,1,5) → c が勝ち
c=(3,4,8) , a=(9,5,1) → a が勝ち
全ての組み合わせの「試合」において条件 勝:負:分≒1:2:0 を満たしていることが確認できます。{1,6,8} vs {2,4,9} vs {3,5,7} も同様です。
ここでは紙と鉛筆だけで見つけられることを示すために、「和が15」という仮の型を設定して探しましたが、次のようにプログラムを組んで調べてみても、他の分け方はありませんでした。偶然なのかもしれませんが、必然となる理由があるのかもしれません。
#include<stdio.h>
int wc[300][4],c_max;
int s(int x){return (x!=0)*(1-2*(x<0));}
int s(int x,int y,int z){return s(s(x)+s(y)+s(z));}
int vs(int *a,int *b){
return s(a[0]-b[0],a[1]-b[1],a[2]-b[2])+
s(a[0]-b[0],a[1]-b[2],a[2]-b[1])+
s(a[0]-b[1],a[1]-b[0],a[2]-b[2])+
s(a[0]-b[1],a[1]-b[2],a[2]-b[0])+
s(a[0]-b[2],a[1]-b[0],a[2]-b[1])+
s(a[0]-b[2],a[1]-b[1],a[2]-b[0]);
}
void initial(void){
int i,j,k,c,*p;
for(i=1,c=0;i<8;i++)for(j=i+1;j<9;j++)for(k=j+1;k<10;k++){
wc[c][0]=i;
wc[c][1]=j;
wc[c][2]=k;
wc[c][3]=(1<<i) + (1<<j) +(1<<k);
c++;
}
c_max=c;
for(i=0,p=wc[0];i<c_max;i++,p=wc[i])
printf("%3d:{%d,%d,%d},%03o\n",i+1,p[0],p[1],p[2],p[3]/2);
printf("\n");
for(i=0,c=0;i<c_max;i++)for(j=i+1;j<c_max;j++){
if(wc[i][3] & wc[j][3])continue;
for(k=j+1;k<c_max;k++){
if(wc[i][3] & wc[k][3] || wc[j][3] & wc[k][3])continue;
printf("%3d:",c+1);
printf("{%d,%d,%d}," ,wc[i][0],wc[i][1],wc[i][2]);
printf("{%d,%d,%d}," ,wc[j][0],wc[j][1],wc[j][2]);
printf("{%d,%d,%d}\n",wc[k][0],wc[k][1],wc[k][2]);
c++;
}
}
printf("\n");
}
int main(int argc,char *argv[]){
int i,j,k,c,vs12,vs23,vs31,sol_h_c=0;
initial();
for(i=0;i<c_max;i++)for(j=i+1;j<c_max;j++){
if(wc[i][3] & wc[j][3])continue;
for(k=j+1;k<c_max;k++){
if(wc[i][3] & wc[k][3] || wc[j][3] & wc[k][3])continue;
vs12=vs(&wc[i][0],&wc[j][0]);if(vs12 != 2 && vs12 != -2)continue;
vs23=vs(&wc[j][0],&wc[k][0]);if(vs23 != vs12)continue;
vs31=vs(&wc[k][0],&wc[i][0]);if(vs31 != vs12)continue;
printf("%3d:",sol_h_c+1);
printf("{%d,%d,%d}," ,wc[i][0],wc[i][1],wc[i][2]);
printf("{%d,%d,%d}," ,wc[j][0],wc[j][1],wc[j][2]);
printf("{%d,%d,%d}\n",wc[k][0],wc[k][1],wc[k][2]);
sol_h_c++;
}
}
printf("end\n");
return 0;
}
1:{1,2,3},007
2:{1,2,4},013
3:{1,2,5},023
4:{1,2,6},043
5:{1,2,7},103
6:{1,2,8},203
(中略)
79:{5,7,9},520
80:{5,8,9},620
81:{6,7,8},340
82:{6,7,9},540
83:{6,8,9},640
84:{7,8,9},700
1:{1,2,3},{4,5,6},{7,8,9}
2:{1,2,3},{4,5,7},{6,8,9}
3:{1,2,3},{4,5,8},{6,7,9}
4:{1,2,3},{4,5,9},{6,7,8}
5:{1,2,3},{4,6,7},{5,8,9}
6:{1,2,3},{4,6,8},{5,7,9}
(中略)
275:{1,8,9},{2,4,5},{3,6,7}
276:{1,8,9},{2,4,6},{3,5,7}
277:{1,8,9},{2,4,7},{3,5,6}
278:{1,8,9},{2,5,6},{3,4,7}
279:{1,8,9},{2,5,7},{3,4,6}
280:{1,8,9},{2,6,7},{3,4,5}
1:{1,5,9},{2,6,7},{3,4,8}
2:{1,6,8},{2,4,9},{3,5,7}
end
では、本文に戻ります。
この問題の場合、「試合」は三つの「勝負」からなります。各組み合わせ、複数にわたる「試合」において引き分けはありませんでした。
これはどの「勝負」においても引き分けがなかったことを意味します。ある「試合」において、引き分けになる「勝負」があったら、(三竦み状態が条件である以上)「試合」の引き分けがどこかで起こります。それがなかったのだから、どの「勝負」においても引き分けが無かったと結論できます。
カード同士の「勝負」において、引き分けが無かったということは、カード間の数値の差が1以上あったと言うことです。
問題では、使われた数字の合計の最大値が設定されています。「無駄な差」があれば、「勝負」・「試合」の結果に影響を与えず、「差を詰める」ことで合計を小さくできます。
これらの考察から、カードに書かれた数値は0以上の整数に限定してよいことが分かります。
使うのは0以上の整数ですが、トランプなどで実験を行うことを想定して、「1から9までが書かれたカードを3つに分配」という設定の問題をヒントとしました。
ヒントの設定において三竦み状態になる分配方法を見つけることがこの問題解決への近道になります。
そして、その方法がヒントの解説で示したように見つかりました。
数値の合計と共に再掲します。
{1,5,9} vs {2,6,7} vs {3,4,8} 数値合計45
{1,6,8} vs {2,4,9} vs {3,5,7} 数値合計45
まず、1~9という数字を、0~8という数字に変換させることで、合計を45から36に変えることができます。やってみましょう。
{0,4,8} vs {1,5,6} vs {2,3,7} 数値合計36
{0,5,7} vs {1,3,8} vs {2,4,6} 数値合計36
ここで改めて考察します。
カード間の数字の差が1以上であるというのは、「勝負」を行うカード間において必要な条件です。「勝負」を行わないカード間においては必要ありません。
何を言いたいのかというと、ある人物の持ちカードに連続する二数があれば、その二数の差1は「無駄な差」です。「勝負」する可能性を考慮して、全てのカード間に1以上の差があるように、1~9のカードを採用したけど、同じチームになれば「勝負」することはなく、「無駄な差」になっているのです。
そのような場合、「詰める」ことが可能です。それが、前者には二箇所あります。再掲します。
{0,4,8} vs {1,5,6} vs {2,3,7} 数値合計36
{1,5,6}の6を5に変化させても、「試合」の結果に変化はありません。
これに伴い、他の人物のカード7を8に、8を7に変化させます。
{0,4,7} vs {1,5,5} vs {2,3,6} 数値合計33
さらに、{2,3,6}の3を2にし、4以上のカードを全て1減じます。
{0,3,6} vs {1,4,4} vs {2,2,5} 数値合計27
合計が27、各プレイヤーの合計も全て9になりました。
これが、正解のカード内容です。問題の設定に合うよう人物を充てると、
A={0,3,6} , B={1,4,4} , C={2,2,5}
のように9枚のカードが確定し、そしてこれが唯一の方法です。
問題は、「合計が9以下になるような0以上の3実数」を書くことになっていました。考察から整数に限定してよいことが分かります。実数を対象に全組み合わせ検索等できませんが、整数ならプログラムにできます。
次のプログラムでは、合計が9以下ではなく、12以下にして走らせています。三数の合計が27になっているのは、最初に出力されたものだけであることをご確認下さい。
#include<stdio.h>
#define N 12
int wc[800][3],c_max;
int s(int x){return (x!=0)*(1-2*(x<0));}
int s(int x,int y,int z){return s(s(x)+s(y)+s(z));}
int vs(int *a,int *b){
int s1=s(a[0]-b[0],a[1]-b[1],a[2]-b[2]),
s2=s(a[0]-b[0],a[1]-b[2],a[2]-b[1]),
s3=s(a[0]-b[1],a[1]-b[0],a[2]-b[2]),
s4=s(a[0]-b[1],a[1]-b[2],a[2]-b[0]),
s5=s(a[0]-b[2],a[1]-b[0],a[2]-b[1]),
s6=s(a[0]-b[2],a[1]-b[1],a[2]-b[0]);
return (s1==0||s2==0||s3==0||s4==0||s5==0||s6==0)?0:s1+s2+s3+s4+s5+s6;
}
int main(int argc,char *argv[]){
int i,j,k,c=0,*p,vs12,vs23,vs31,sol_c=0;
for(i=0;i<=N;i++)for(j=i;j<=N;j++)for(k=j;k<=N;k++){
if(i+j+k>N)continue;
wc[c][0]=i;
wc[c][1]=j;
wc[c][2]=k;
c++;
}
c_max=c;
for(i=0,p=wc[0];i<c_max;i++,p=wc[i])
printf("%3d:{%d,%d,%d}\n",i+1,p[0],p[1],p[2]);
printf("\n");
for(i=0;i<c_max;i++)for(j=i+1;j<c_max;j++)for(k=j+1;k<c_max;k++){
vs12=vs(&wc[i][0],&wc[j][0]);if(vs12 != 2 && vs12 != -2)continue;
vs23=vs(&wc[j][0],&wc[k][0]);if(vs12 != vs23)continue;
vs31=vs(&wc[k][0],&wc[i][0]);if(vs31 != vs12)continue;
printf("%3d:",sol_c+1);
printf("{%d,%d,%d}," ,wc[i][0],wc[i][1],wc[i][2]);
printf("{%d,%d,%d}," ,wc[j][0],wc[j][1],wc[j][2]);
printf("{%d,%d,%d}, ",wc[k][0],wc[k][1],wc[k][2]);
printf(" %d\n",wc[i][0]+wc[i][1]+wc[i][2]+wc[j][0]+
wc[j][1]+wc[j][2]+wc[k][0]+wc[k][1]+wc[k][2]);
sol_c++;
}
printf("end\n");
return 0;
}
1:{0,0,0}
2:{0,0,1}
3:{0,0,2}
4:{0,0,3}
5:{0,0,4}
6:{0,0,5}
(中略)
97:{3,3,4}
98:{3,3,5}
99:{3,3,6}
100:{3,4,4}
101:{3,4,5}
102:{4,4,4}
1:{0,3,6},{1,4,4},{2,2,5}, 27
2:{0,3,7},{1,4,4},{2,2,5}, 28
3:{0,3,7},{1,4,4},{2,2,6}, 29
4:{0,3,7},{1,4,5},{2,2,6}, 30
5:{0,3,7},{1,5,5},{2,2,6}, 31
6:{0,3,8},{1,4,4},{2,2,5}, 29
7:{0,3,8},{1,4,4},{2,2,6}, 30
8:{0,3,8},{1,4,4},{2,2,7}, 31
9:{0,3,8},{1,4,5},{2,2,6}, 31
10:{0,3,8},{1,4,5},{2,2,7}, 32
11:{0,3,8},{1,4,6},{2,2,7}, 33
12:{0,3,8},{1,5,5},{2,2,6}, 32
13:{0,3,8},{1,5,5},{2,2,7}, 33
14:{0,3,8},{1,5,6},{2,2,7}, 34
15:{0,3,9},{1,4,4},{2,2,5}, 30
16:{0,3,9},{1,4,4},{2,2,6}, 31
17:{0,3,9},{1,4,4},{2,2,7}, 32
18:{0,3,9},{1,4,4},{2,2,8}, 33
19:{0,3,9},{1,4,5},{2,2,6}, 32
20:{0,3,9},{1,4,5},{2,2,7}, 33
21:{0,3,9},{1,4,5},{2,2,8}, 34
22:{0,3,9},{1,4,6},{2,2,7}, 34
23:{0,3,9},{1,4,6},{2,2,8}, 35
24:{0,3,9},{1,4,7},{2,2,8}, 36
25:{0,3,9},{1,5,5},{2,2,6}, 33
26:{0,3,9},{1,5,5},{2,2,7}, 34
27:{0,3,9},{1,5,5},{2,2,8}, 35
28:{0,3,9},{1,5,6},{2,2,7}, 35
29:{0,3,9},{1,5,6},{2,2,8}, 36
30:{0,4,7},{1,5,5},{2,2,6}, 32
31:{0,4,7},{1,5,5},{2,3,6}, 33
32:{0,4,7},{1,5,5},{3,3,6}, 34
33:{0,4,7},{2,5,5},{3,3,6}, 35
34:{0,4,8},{1,5,5},{2,2,6}, 33
35:{0,4,8},{1,5,5},{2,2,7}, 34
36:{0,4,8},{1,5,5},{2,3,6}, 34
37:{0,4,8},{1,5,5},{2,3,7}, 35
38:{0,4,8},{1,5,5},{3,3,6}, 35
39:{0,4,8},{1,5,6},{2,2,7}, 35
40:{0,4,8},{1,5,6},{2,3,7}, 36
41:{0,4,8},{2,5,5},{3,3,6}, 36
42:{0,5,7},{1,3,8},{2,4,6}, 36
43:{1,4,7},{2,5,5},{3,3,6}, 36
end
#数理パズル #論理パズル #数学 #9枚の白紙カード #三竦み #プログラム