Algorithm 如何用正方形完全填充固定的矩形?
这是背包算法还是装箱?我找不到一个精确的解决方案,但基本上我有一个固定的矩形区域,我想用完美的正方形填充,代表我的项目,每个项目都有不同的权重,这将影响它们相对于其他项目的大小 它们将从左上角到右下角从大到小排序 此外,尽管我需要完美的正方形,但最终允许一些非均匀缩放填充整个空间,只要它们仍保留其相对面积,并且非均匀缩放以尽可能少的量完成 我可以用什么算法来实现这一点呢?有一个问题是由于长垣广史和安倍晋介。我在C++中实现它,注意用最坏情况递归深度O(log n)获得最坏情况O(n log n)-时间实现。如果n≤ 100,这些预防措施可能是不必要的Algorithm 如何用正方形完全填充固定的矩形?,algorithm,math,knapsack-problem,packing,bin-packing,Algorithm,Math,Knapsack Problem,Packing,Bin Packing,这是背包算法还是装箱?我找不到一个精确的解决方案,但基本上我有一个固定的矩形区域,我想用完美的正方形填充,代表我的项目,每个项目都有不同的权重,这将影响它们相对于其他项目的大小 它们将从左上角到右下角从大到小排序 此外,尽管我需要完美的正方形,但最终允许一些非均匀缩放填充整个空间,只要它们仍保留其相对面积,并且非均匀缩放以尽可能少的量完成 我可以用什么算法来实现这一点呢?有一个问题是由于长垣广史和安倍晋介。我在C++中实现它,注意用最坏情况递归深度O(log n)获得最坏情况O(n log n)
#include <algorithm>
#include <iostream>
#include <random>
#include <vector>
namespace {
struct Rectangle {
double x;
double y;
double width;
double height;
};
Rectangle Slice(Rectangle &r, const double beta) {
const double alpha = 1 - beta;
if (r.width > r.height) {
const double alpha_width = alpha * r.width;
const double beta_width = beta * r.width;
r.width = alpha_width;
return {r.x + alpha_width, r.y, beta_width, r.height};
}
const double alpha_height = alpha * r.height;
const double beta_height = beta * r.height;
r.height = alpha_height;
return {r.x, r.y + alpha_height, r.width, beta_height};
}
void LayoutRecursive(const std::vector<double> &reals, const std::size_t begin,
std::size_t end, double sum, Rectangle rectangle,
std::vector<Rectangle> &dissection) {
while (end - begin > 1) {
double suffix_sum = reals[end - 1];
std::size_t mid = end - 1;
while (mid > begin + 1 && suffix_sum + reals[mid - 1] <= 2 * sum / 3) {
suffix_sum += reals[mid - 1];
mid -= 1;
}
LayoutRecursive(reals, mid, end, suffix_sum,
Slice(rectangle, suffix_sum / sum), dissection);
end = mid;
sum -= suffix_sum;
}
dissection.push_back(rectangle);
}
std::vector<Rectangle> Layout(std::vector<double> reals,
const Rectangle rectangle) {
std::sort(reals.begin(), reals.end());
std::vector<Rectangle> dissection;
dissection.reserve(reals.size());
LayoutRecursive(reals, 0, reals.size(),
std::accumulate(reals.begin(), reals.end(), double{0}),
rectangle, dissection);
return dissection;
}
std::vector<double> RandomReals(const std::size_t n) {
std::vector<double> reals(n);
std::exponential_distribution<> dist;
std::default_random_engine gen;
for (double &real : reals) {
real = dist(gen);
}
return reals;
}
} // namespace
int main() {
const std::vector<Rectangle> dissection =
Layout(RandomReals(100), {72, 72, 6.5 * 72, 9 * 72});
std::cout << "%!PS\n";
for (const Rectangle &r : dissection) {
std::cout << r.x << " " << r.y << " " << r.width << " " << r.height
<< " rectstroke\n";
}
std::cout << "showpage\n";
}
#include好,让我们假设整数位置和大小(无浮点操作)。要将矩形均匀划分为规则的正方形网格(尽可能大的正方形),单元格的大小将是矩形大小的最大公约数GCD
但是你想要的方块比这个少很多,所以我会尝试这样的方法:
尝试所有方形尺寸a
从1到更小的矩形尺寸
对于每个a
计算剩余矩形的原始正方形网格大小,只要a*a
正方形从中切下
因此,只要将a*a
square切掉,就可以在2个矩形上创建GCD。如果2个矩形中的所有3个大小<代码> > <代码>和GCD大于1(忽略零区域矩形),则考虑<代码> < < /代码>作为有效的解决方案,所以记住它。
在for
循环之后,使用上次找到的有效a
因此,只需将a*a
square添加到您的输出中,然后对a*a
square被切断后保留在原始矩形上的两个矩形再次递归地执行此操作
这里是简单的C++/VCL/OpenGL示例:
//---------------------------------------------------------------------------
#包括
#布拉格语hdrstop
#包括“Unit1.h”
#包括“gl_simple.h”
//---------------------------------------------------------------------------
#pragma包(智能初始化)
#pragma资源“*.dfm”
TForm1*Form1;
//---------------------------------------------------------------------------
类方//简单方
{
公众:
int x,y,a;//角2D位置和大小
square(){x=y=a=0.0;}
平方(int x,int y,int a){x=x;y=y;a=a;}
~square(){}
作废提款()
{
glBegin(GL_线_环);
glVertex2i(x,y);
glVertex2i(x+a,y);
glVertex2i(x+a,y+a);
glVertex2i(x,y+a);
格伦德();
}
};
int rec[4]={20,20760560};//x、 y,a,b
常数int N=1024;//最大平方数
int n=0;//方块数
正方形s[N];//方格
//---------------------------------------------------------------------------
intgcd(inta,intb)//慢欧几里德gcd
{
如果(!b)返回a;
返回gcd(b,a%b);
}
//---------------------------------------------------------------------------
无效计算(整数x0、整数y0、整数xs、整数ys)
{
if((xs==0)| |(ys==0))返回;
常数int x1=x0+xs;
常数int y1=y0+ys;
int a,b,i,x,y;
平方t;
//试着先找到最大的正方形
对于(a=1,b=0;(ax))i=x;
如果((y>0)&(i>y))i=y;
//如果整除比1更好,记住它是更好的解
如果(i>1)b=a;
}a=b;
//找不到更大的正方形,所以使用朴素的正方形网格划分
如果(aI不认为完美的正方形在二进制计算机上总是可能的…更像是一些浮点精度限制,如矩形大小的2^-24。我会计算最大公因数(但浮点1)在第一次迭代中,我们可以将矩形大小浮动对齐到同一个指数,并将尾数用作GCD的整数。换句话说,放大矩形,使其大小为精度限制内的整数如果你想的话,你可以把它们合并成更大的正方形……看这一点,在这里,你需要计算任何浮动大小矩形的GCD。这似乎很难做到,特别是在排序标准下。我知道,它允许对正方形大小或纵横比进行很少的控制。这很容易,但也许你有理由这样做想要正方形。谢谢伙计们,什么是GCD?我刚刚发现它叫树形映射。我想我可以用它。我只是觉得完美的正方形看起来更好。而且在我的情况下,我没有那么多的项目,比如说最多100个。如果你愿意放弃排序,可能可以优化一棵树,使树形映射接近1:1pect比率看起来不像squares@Spektre“允许某些非均匀缩放”引用OP:非均匀缩放是以尽可能少的量完成的
我在你的输出中没有看到正方形…@Spektre这似乎是一个难题。请随意发布你自己的答案。我会的,但有很多关于输入缺失的澄清,如果没有它,回答并实现OP作者想要的不同是浪费时间的输入的组合……看起来他也缺少这方面所需的数学技能(假设GCD是什么)尽管有很高的代表性…但它可能只是太不同的语言…有时我常常不懂英语中的一些数学,因为它使用不同的符号。很多情况下,我会尝试将其移植到C。但是