3本のひもで作る四角形

awkネタ

同じ長さの3本のひもを折り曲げて3つの四角形を作ります。
そのうち2本でそれぞれ長方形を作り、残りの1本は正方形を作ります。
このとき、作った2つの長方形の面積の和が、正方形の面積と同じになることがあります。
(ただし、いずれの長方形、正方形も辺の長さは整数)

例)紐の長さが20の時
1本目 縦1×横9の長方形→面積=9
2本目 縦2×横8の長方形→面積=16
3本目 縦5×横5の正方形→面積=25

さらに、ひもの長さを変えてできる長方形と正方形の組をカウントします。
ただし、同じ比で整数倍のものは1つとしてカウント
例)紐の長さが40の時
1本目 縦2×横18の長方形→面積=36
2本目 縦4×横16の長方形→面積=64
3本目 縦10×横10の正方形→面積=100
紐の長さが60の時
1本目 縦3×横27の長方形→面積=81
2本目 縦6×横24の長方形→面積=114
3本目 縦15×横15の正方形→面積=225

紐の長さを1から500まで変化させる時、2つの長方形の面積の和と
正方形の面積が同じなる組が何通りあるか?

簡単に見えてやってみたら難しかったです。
ポイントは下記の通りです。

  • 正方形の1辺は紐の長さの4分の1
  • 縦の長さが決まると、横の長さは紐の長さを2で割って、縦の長さを引く
  • 縦の長さは正方形の1辺よりも短くする。
#!/usr/bin/awk -f

BEGIN{
    N = 500;
    c = 0;
    for(i = 1; i <= N; i++){
        yoko = 0;
        if(i % 4 == 0){                         # 正方形の1辺は整数
            seihou = i / 4;                     # 正方形の1辺はひもの長さの1/4
            for(tate = 1; tate < seihou; tate++){   # 縦の長さは正方形の1辺よりも短くする
                if(i % 2 == 0){                 # 横の長さは整数
                    yoko = i / 2 - tate;        # 横の長さ
                    for(tate2 = 1; tate2 < seihou; tate2++){    #2本目の縦の長さ
                        yoko2 = i / 2 - tate2;                  # 2本目の横の長さ
                        # 正方形の面積は1本目と2本目の長方形面積の和
                        if(seihou * seihou == tate * yoko + tate2 * yoko2){ 
                            c++;
                            answer[c] = seihou * seihou;    # 正方形の面積
                            one[c] = tate * yoko;           # 最初の長方形
                            two[c] = tate2 * yoko2;         # 2本目の長方形
                        }
                    }
                }
            }
        }
    }
    len =  length(answer);          # 配列の個数
    for(i = 1; i <= len; i++){
        for(j = i + 1; j <= len; j++){
            if(one[i]){
                num = one[j] / one[i];          # 1つ目長方形同士の整数倍
                if(two[i] && two[j] / two[i] == num){ # 2つ目長方形同士の整数場
                    if(answer[i] && answer[j] / answer[i] ==  num){ # 正方形同士の整数倍
                        delete answer[j];
                    }
                }
            }
        }
    }
    for(k in answer){
        if(answer[k]){      # 削除されていない配列の個数
            count++;
        }
    }
    print count / 2;        # 縦と横を入れ替えたものを除外
}

実行してみます。

awk -f q16.awk
20

rubyとかだと、ライブラリが揃っているので、もっと短く出来るかもしれません。
awkを使ったアルゴリズムの勉強なので、これで良しとします。