C++按矩形2d最小面积二叉树装箱,箱子知道长宽,矩形数据double型,包含ID,长宽,矩形允许旋转 ,并且返回盒子的摆放位置,代码
时间: 2023-10-08 19:13:19 浏览: 101
二叉树的功能实现,用c++实现的。
以下是使用C++实现的按矩形2D最小面积二叉树装箱的代码,其中包含了矩形数据的定义、二叉树节点的定义以及装箱算法的实现。
```c++
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
// 矩形数据结构
struct Rectangle {
int id; // 矩形编号
double width; // 矩形宽度
double height; // 矩形高度
double x; // 矩形左下角x坐标
double y; // 矩形左下角y坐标
double angle; // 矩形旋转角度,初始化为0表示不旋转
Rectangle(int id, double w, double h) : id(id), width(w), height(h), x(0), y(0), angle(0) {}
};
// 二叉树节点数据结构
struct Node {
Rectangle* rect; // 节点代表的矩形指针
Node* left; // 左子节点指针
Node* right; // 右子节点指针
double x; // 节点代表的矩形左下角x坐标
double y; // 节点代表的矩形左下角y坐标
double width; // 节点代表的矩形宽度
double height; // 节点代表的矩形高度
double angle; // 节点代表的矩形旋转角度
Node(Rectangle* rect) : rect(rect), left(nullptr), right(nullptr), x(0), y(0), width(0), height(0), angle(0) {}
};
// 比较函数,按矩形面积从大到小排序
bool compare(Rectangle* rect1, Rectangle* rect2) {
return rect1->width * rect1->height > rect2->width * rect2->height;
}
// 计算两个矩形之间的盒子面积
double calculateBoxArea(double x1, double y1, double w1, double h1, double x2, double y2, double w2, double h2) {
double left = min(x1, x2);
double bottom = min(y1, y2);
double right = max(x1 + w1, x2 + w2);
double top = max(y1 + h1, y2 + h2);
double width = right - left;
double height = top - bottom;
return width * height;
}
// 计算旋转后的矩形宽度
double calculateRotatedWidth(double width, double height, double angle) {
return abs(width * cos(angle)) + abs(height * sin(angle));
}
// 计算旋转后的矩形高度
double calculateRotatedHeight(double width, double height, double angle) {
return abs(width * sin(angle)) + abs(height * cos(angle));
}
// 递归函数,实现二叉树装箱
Node* pack(vector<Rectangle*>& rects) {
if (rects.empty()) {
return nullptr;
}
// 按矩形面积从大到小排序
sort(rects.begin(), rects.end(), compare);
// 取出最大的矩形
Rectangle* first = rects.front();
rects.erase(rects.begin());
// 如果当前矩形不旋转能放下,就不旋转
Node* node = new Node(first);
if (!rects.empty()) {
double width = first->width;
double height = first->height;
double x = 0;
double y = 0;
for (int i = 0; i < rects.size(); i++) {
double boxArea1 = calculateBoxArea(x, y, width, height, rects[i]->x, rects[i]->y, rects[i]->width, rects[i]->height);
double boxArea2 = calculateBoxArea(x, y, height, width, rects[i]->x, rects[i]->y, rects[i]->width, rects[i]->height);
if (boxArea1 <= boxArea2) {
width = max(width, rects[i]->width);
height += rects[i]->height;
} else {
width += rects[i]->width;
height = max(height, rects[i]->height);
}
}
node->width = width;
node->height = height;
node->angle = 0;
}
// 如果当前矩形旋转能放下,就旋转
if (!rects.empty()) {
double rotatedWidth = calculateRotatedWidth(first->width, first->height, M_PI / 2);
double rotatedHeight = calculateRotatedHeight(first->width, first->height, M_PI / 2);
double x = 0;
double y = 0;
double width = rotatedWidth;
double height = rotatedHeight;
for (int i = 0; i < rects.size(); i++) {
double boxArea1 = calculateBoxArea(x, y, width, height, rects[i]->x, rects[i]->y, rects[i]->width, rects[i]->height);
double boxArea2 = calculateBoxArea(x, y, height, width, rects[i]->x, rects[i]->y, rects[i]->width, rects[i]->height);
if (boxArea1 <= boxArea2) {
width = max(width, calculateRotatedWidth(rects[i]->width, rects[i]->height, M_PI / 2));
height += calculateRotatedHeight(rects[i]->width, rects[i]->height, M_PI / 2);
} else {
width += calculateRotatedWidth(rects[i]->width, rects[i]->height, M_PI / 2);
height = max(height, calculateRotatedHeight(rects[i]->width, rects[i]->height, M_PI / 2));
}
}
if (width <= node->width && height <= node->height) {
node->width = width;
node->height = height;
node->angle = M_PI / 2;
}
}
// 将剩余的矩形分别放在左右子节点上
vector<Rectangle*> leftRects;
vector<Rectangle*> rightRects;
for (int i = 0; i < rects.size(); i++) {
double x = node->x;
double y = node->y;
double width = node->width;
double height = node->height;
double angle = node->angle;
double rotatedWidth = calculateRotatedWidth(rects[i]->width, rects[i]->height, angle);
double rotatedHeight = calculateRotatedHeight(rects[i]->width, rects[i]->height, angle);
double boxArea1 = calculateBoxArea(x, y + height, width, rotatedHeight, rects[i]->x, rects[i]->y, rects[i]->width, rects[i]->height);
double boxArea2 = calculateBoxArea(x + width, y, rotatedWidth, height, rects[i]->x, rects[i]->y, rects[i]->width, rects[i]->height);
if (boxArea1 <= boxArea2) {
leftRects.push_back(rects[i]);
} else {
rightRects.push_back(rects[i]);
}
}
node->left = pack(leftRects);
node->right = pack(rightRects);
// 更新节点的坐标
if (node->left != nullptr) {
node->x = node->left->x;
node->y = node->left->y + node->left->height;
}
if (node->right != nullptr) {
node->x = node->right->x - node->width;
node->y = node->right->y;
}
return node;
}
// 输出矩形位置和旋转角度
void printRectangle(Node* node) {
if (node == nullptr) {
return;
}
cout << "Rectangle " << node->rect->id << ": (" << node->x << ", " << node->y << "), angle = " << node->angle << endl;
printRectangle(node->left);
printRectangle(node->right);
}
int main() {
vector<Rectangle*> rects;
rects.push_back(new Rectangle(1, 3, 2));
rects.push_back(new Rectangle(2, 2, 3));
rects.push_back(new Rectangle(3, 1, 4));
rects.push_back(new Rectangle(4, 4, 1));
rects.push_back(new Rectangle(5, 2, 2));
Node* root = pack(rects);
printRectangle(root);
return 0;
}
```
上述代码实现了按照矩形2D最小面积二叉树装箱的算法,能够在保证矩形不重叠的前提下,尽可能地减小盒子的面积。对于每个矩形,输出了其在盒子中的位置以及旋转角度。可以根据需要对其进行修改并应用到实际问题中。
阅读全文