简化问题 :
四个长方形长宽都已知, 四个面积 S1, S2, S3, S4 已知, 总面积 S = S1 + S2 + S3 + S4 已知
于是枚举长边为length, 宽为width = S / length, 问题转化为, 这四个长方形能否塞进 length * width 的长方形中?
规定小长方形的 l > w, 大长方形的 length > width
1. 如果问一个长宽已知的长方形, 问能否正好(不留空)放入length * width的长方形中, 只要长边 == length, 短边 == width 即可
2. 如果问两个长宽已知的长方形, 如果能放入, 那么必然有一个长方形的 长 / 宽 正好和大长方形的一边相等, 剩下一个长方形和剩余部分(也是长方形), 转化为问题1
3. 如果问三个长宽已知的长方形, 如果能放入, 那么必然有一个长方形 长 / 宽 正好和大长方形的一边相等, 剩下二个长方形和剩余部分转化为问题2
4. 可以看出这已经转化为一个递归问题了, 如果给4个? 我们希望先放一个长方形之后转化为问题3
枚举长 length, 此时宽已知, 为 S / length
先放入长边最长的长方形, 用来和大长方形的匹配, 此时会出现3种情况
一. w > width 不可行
二. l == length 或 l == width 或 w == width, 大长方形剩下一块和三个小长方形匹配, 转化为上述问题
三. l < length 且 w < width, 留下一个不规则的图形, 对这个图形进行分解, 分为3块, S1, S2, S3
显然(弱渣不会证明), 剩下的S1 或 S2, 必然能和3个长方形其中之一匹配, 枚举并成功匹配后, 转化为问题2
于是放4个的情况就解决了...
这个问题的来路让我很惭愧... 贴出代码, 欢迎指正
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef struct { int l, w; } Rec; Rec r[5]; bool vis[5]; bool Check(int length, int width, int num) { if(length < width) swap(length, width); if(num == 1) { for(int i = 1; i < 4; i++) { if(vis[i]) continue; if(r[i].l == length && r[i].w == width) return true; } } else if(num == 2) { for(int i = 1; i < 4; i++) { if(vis[i]) continue; if(r[i].l == length) { vis[i] = 1; if(Check(length, width - r[i].w, 1)) return 1; else return 0; } else if(r[i].l == width) { vis[i] = 1; if(Check(length - r[i].w, width, 1)) return 1; else return 0; } else if(r[i].w == width) { vis[i] = 1; if(Check(length - r[i].l, width, 1)) return 1; else return 0; } } } else if(num == 3) { for(int i = 1; i < 4; i++) { if(vis[i]) continue; if(r[i].l == length) { vis[i] = 1; if(Check(length, width - r[i].w, 2)) return 1; else return 0; } else if(r[i].l == width) { vis[i] = 1; if(Check(length - r[i].w, width, 2)) return 1; else return 0; } else if(r[i].w == width) { vis[i] = 1; if(Check(length - r[i].l, width, 1)) return 1; else return 0; } } } else { vis[0] = 1; if(r[0].w > width) return 0; if(r[0].l == length) { if(Check(length, width - r[0].w, 3)) return 1; else return 0; } else if(r[0].l == width) { if(Check(length - r[0].w, width, 3)) return 1; else return 0; } else if(r[0].w == width) { if(Check(length - r[0].l, width, 3)) return 1; else return 0; } else if(r[0].l < length) { int s1_l = length - r[0].l; int s1_w = r[0].w; int s2_l = r[0].l; int s2_w = width - r[0].w; for(int i = 1; i < 4; i++) { if(r[i].l == s1_l && r[i].w == s1_w || r[i].l == s1_w && r[i].w == s1_l) { vis[i] = 1; int s3_l = s1_l + s2_l; int s3_w = s2_w; if(Check(s3_l, s3_w, 2)) return 1; else return 0; } else if(r[i].l == s2_l && r[i].w == s2_w || r[i].l == s2_w && r[i].w == s2_l) { vis[i] = 1; int s3_l = s1_l; int s3_w = s1_w + s2_w; if(Check(s3_l, s3_w, 2)) return 1; else return 0; } } } } return 0; } bool cmp(Rec a, Rec b) { return a.l > b.l; } int main() { int t; scanf("%d", &t); int length, width; while(t--) { int sum = 0; for(int i = 0; i < 4; i++) { scanf("%d %d", &r[i].l, &r[i].w); if(r[i].l < r[i].w) swap(r[i].l, r[i].w); sum += r[i].l * r[i].w; } sort(r, r+4, cmp); bool flag = 0; for(int i = 1; i <= sqrt(sum); i++) { if(sum % i == 0) { length = sum / i; width = i; memset(vis, 0, sizeof(vis)); if(Check(length, width, 4)) { flag = 1; break; } } } if(flag) printf("Yes %d %d\n", length, width); else printf("No\n"); } return 0; }