程序员的算法趣题:Q16 三根绳子折成四边形(Java版)

探讨如何通过编程找出特定长度的绳子摆成的两个长方形面积之和等于一个正方形面积的所有组合,同时考虑了比例相同组合的唯一性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目说明

假设分别将 3 根长度相同的绳子摆成 3 个四边形。
其中 2 根摆成长方形,剩下 1 根摆成正方形。
这时,会出现 2 个长方形的面积之和等于正方形面积的情况
(假设长方形和正方形的各边长都为整数)。

例如:
● 绳子长度为20时,可以折出以下这些正方形和长方形。
 第 1 根 长 1× 宽 9 的长方形 → 面积= 9
 第 2 根 长 2× 宽 8 的长方形 → 面积= 16
 第 3 根 长 5× 宽 5 的正方形 → 面积= 25

进一步改变绳子长度并摆成长方形和正方形,统计满足条件的长方形和正方形的组合。
这里,将同比整数倍的结果看作同一种解法。

例如:绳子长度为40, 60, …时,
可以通过对上例进行等比运算得出以下这些正方形和长方形的组合,
但要将它们看作同一种解法,所以这一类只统计为1种。

● 绳子长度= 40
 第 1 根 长 2× 宽 18 的长方形 → 面积= 36
 第 2 根 长 4× 宽 16 的长方形 → 面积= 64
 第 3 根 长 10× 宽 10 的正方形 → 面积= 100
● 绳子长度= 60
 第 1 根 长 3× 宽 27 的长方形 → 面积= 81
 第 2 根 长 6× 宽 24 的长方形 → 面积= 144
 第 3 根 长 15× 宽 15 的正方形 → 面积= 225

求绳子长度从 1 增长到 500 时,
共有多少种组合能使摆出的 2 个长方形面积之和等于正方形的面积?

思路

1.因为长宽均为整数,所以长度不能被4整除的绳子直接略过
2.通过绳子的长度可以计算出正方形的边长:len / 4
3.通过绳子的长度可以计算出长方形长宽的所有可能性:宽 < 正方形的边长 < 长
4.双重循环罗列出两个长方形的所有长宽组合,并计算面积之和
5.找出面积之和等于正方形面积的结果
6.对得到的结果进行筛选
    1) 长方形自身的长宽互换记为同一个长方形;==> 循环中加入(宽 < 正方形的边长 < 长)条件可以排除这种情况
    2) 两个长方形的交换记为同一种组合;==> 使用List<String>记录第一个长方形的所有长宽组合,然后对第二个长方形的长宽组合进行判断是否已经存在
    3) 相同比例的组合记为同一种;==> 使用HashMap<Integer,Integer>记录每种正确结果中两个长方形的长宽比(因为List<String>已经规避掉了长方形交换的情况,所以Map中只存一个长方形的长宽比即可)

代码

private static Map<Double,Double> hmap = new HashMap<>(); // 存放两个长方形的宽高比
private static int count = 0; // 统计成功组合的数量
public static void main(String[] args) {
    // 绳子长度从4~500
    for(int l = 4; l <= 500; l += 4){
        print(l);
    }
    System.out.println("count = " + count);
}
/**
 * 打印出指定长度的绳子能得到的所有正确组合
 * @param len 绳子长度
 */
public static void print(int len){
    if(len < 4 || len % 4 != 0) return ; // 因为要求正方形长方形边长均为整数,所以错误长度直接略过

    // 正方形的面积
    int square = (len / 4 ) * (len / 4);

    // 记录第一个长方形每一种长宽组合。用于判断某一种长宽组合是否已存在
    List<String> list = new ArrayList<>(); 

    // a是第一个矩形的宽;b是第一个矩形的长
    for(int a = 1,b = len / 2 - a ; a < len / 4; a ++, b--){ // 宽 < 正方形边长 < 长。
        list.add(a+","+b); // 记录第一个长方形的每一组长宽

        // m是第二个矩形的宽;n是第二个矩形的长
        for(int m = 1,n = len / 2 - m ; m < len / 4; m ++, n--){
            if(a*b + m*n == square){  // 两个长方形的面积之和等于正方形的面积
                if(hmap.containsKey(1.0*b/a)){  // 判断长宽比是否已经存在过
                    if(Double.compare(hmap.get(1.0*b/a), 1.0*n/m) == 0){ // 已存在
                        continue; // 相同比例的长宽组合记为一种
                    }
                }
                if(list.contains(m+","+n)) continue; // 判断第二个长方形的长宽组合是否是第一个长方形使用过的

                hmap.put(1.0*b/a, 1.0*n/m); // 第一个矩形的长宽比;第二个矩形的长宽比
                // hmap.put(1.0*n/m, 1.0*b/a); // 如果不使用List,也可以加上这一句来避免两个长方形交换的情况
                count ++; // 正确组合+1
                System.out.println(a + " * " + b + " + " + m + " * " + n + " = " + (len/4) + " * " + (len/4) + " --> " + square);
            }
        }
    }
}

 结果

1 * 9 + 2 * 8 = 5 * 5 --> 25
1 * 25 + 8 * 18 = 13 * 13 --> 169
2 * 32 + 9 * 25 = 17 * 17 --> 289
1 * 49 + 18 * 32 = 25 * 25 --> 625
8 * 50 + 9 * 49 = 29 * 29 --> 841
2 * 72 + 25 * 49 = 37 * 37 --> 1369
1 * 81 + 32 * 50 = 41 * 41 --> 1681
8 * 98 + 25 * 81 = 53 * 53 --> 2809
1 * 121 + 50 * 72 = 61 * 61 --> 3721
2 * 128 + 49 * 81 = 65 * 65 --> 4225
9 * 121 + 32 * 98 = 65 * 65 --> 4225
18 * 128 + 25 * 121 = 73 * 73 --> 5329
1 * 169 + 72 * 98 = 85 * 85 --> 7225
8 * 162 + 49 * 121 = 85 * 85 --> 7225
9 * 169 + 50 * 128 = 89 * 89 --> 7921
25 * 169 + 32 * 162 = 97 * 97 --> 9409
2 * 200 + 81 * 121 = 101 * 101 --> 10201
18 * 200 + 49 * 169 = 109 * 109 --> 11881
1 * 225 + 98 * 128 = 113 * 113 --> 12769
8 * 242 + 81 * 169 = 125 * 125 --> 15625
count = 20
(如果长方形自身的长宽交换算两种,则结果*2)
(如果两个长方形位置交换算两种,则结果*2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值