在偶数维s
的方阵中,有s/4(s/2+1)
种类型的正方形,可以在矩阵周围以七种不同的方式反映出来。例如,10 x 10矩阵在下图中具有独特的正方形颜色:
这15个方块可以以7种不同的方式围绕矩阵的水平轴,垂直轴和对角线反射。
假设为n x n数组的每种类型的元素分配了唯一值,其中n是偶数,填充矩阵的最有效方法是什么(用C或Java)?换句话说,给定您希望的任何结构中的15个值的列表,您需要通过反射使用15个值填充10 x 10阵列的其余部分。什么是最快的算法?
作为一个例子,这是我第一次尝试(注意它使用基于一个的数组):
public static int[][] valueSquare = new int[11][11];
public static int[][] valueSquareType = {
{ 0, 40, 2, 12, 15, 20 },
{ 0, 2, 1, 4, 8, 12 },
{ 0, 12, 4, 25, 20, 15 },
{ 0, 15, 8, 20, 22, 18 },
{ 0, 20, 12, 15, 18, 0 },
};
static {
for( int x = 1; x <= 5; x++ ) for( int y = 1; y <= 5; y++ ) valueSquare[ 11 - x ][ y ] = valueSquareType[x][y];
for( int x = 1; x <= 5; x++ ) for( int y = 1; y <= 5; y++ ) valueSquare[ 11 - x ][ 11 - y ] = valueSquareType[x][y];
for( int x = 1; x <= 5; x++ ) for( int y = 1; y <= 5; y++ ) valueSquare[ x ][ 11 - y ] = valueSquareType[x][y];
}
对此的一个反对意见是它有一个冗余的起始器阵列,它反映了三种方式,而不是一个反映7种方式的最小起始器阵列。理想情况下,我想要一个初始数组,只有15个键值。此外,我尝试的循环可能不是最快的方法。
答案 0 :(得分:4)
假设这是你的意思:
考虑到左上角的黑色区域,我们只需迭代该区域中的所有元素(i, j)
并在镜像后计算其在其他区域中的位置(对角线重叠,因此我将它们标记为灰色,但是公式也考虑它们,你也可以将它们应用于给定的对角线元素):
假设0索引
(i, j) -> (i, n - j - 1) # red area
-> (j, n - i - 1) # yellow area
-> (j, i) # teal area
-> (n - i - 1, j) # green area
-> (n - i - 1, n - j - 1) # blue area
-> (n - j - 1, n - i - 1) # pink area
-> (n - j - 1, i) # orange area
因此迭代每个给定的黑色元素并将其复制到其他区域的7个位置。例如:
#include <iostream>
using namespace std;
int v[6][6] = {
{ 0, 3, 2, 12, 15, 20 },
{ 0, 2, 1, 4, 8, 12 },
{ 0, 12, 4, 25, 20, 15 },
{ 0, 15, 8, 20, 22, 18 },
{ 0, 20, 12, 15, 18, 0 },
};
int main()
{
int n = 6;
// iterate given black area:
for (int i = 0; i < n / 2; ++i)
{
for (int j = i; j < n / 2; ++j)
{
v[i][n - j - 1] = v[i][j]; // copy to red
v[j][n - i - 1] = v[i][j]; // copy to yellow
v[j][i] = v[i][j]; // copy to teal
v[n - i - 1][j] = v[i][j]; // copy to green
v[n - i - 1][n - j - 1] = v[i][j]; // copy to blue
v[n - j - 1][n - i - 1] = v[i][j]; // copy to pink
v[n - j - 1][i] = v[i][j]; // copy to orange;
}
}
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
cout << v[i][j] << " ";
}
cout << endl;
}
return 0;
}
输出:
0 3 2 2 3 0
3 2 1 1 2 3
2 1 4 4 1 2
2 1 4 4 1 2
3 2 1 1 2 3
0 3 2 2 3 0
这似乎是你追求的目标。
答案 1 :(得分:1)
除非我遗漏了什么比这更快的东西?
for (int i = 1; i < n/2; i++) {
for (int j = 0; j < i; j++) {
M[i][j] = M[j][i]; // first complete the first quadrant
}
}
for (int i = 0; i<n/2; i++) {
for (int j = n/2; j < n; j++) {
// then perform the three needed symmetries
M[i][j] = M[i][n-j-1];
M[n-i-1][j] = M[i][n-j-1];
M[n-i-1][n-j-1] = M[i][n-j-1];
}
}
答案 2 :(得分:1)
首先我会认为你做了对角线反射。然后你有一个填充矩阵的四分之一。这是我猜的最棘手的部分因为每列都有不同的长度。也许是这样的: 4 = s / 2-1和10 = s
ref
然后你只需要对角线和水平镜像它。
for(int j=0;j<4;j++)
{
for(int i=j;i<4;i++)
{
array[i+1][j]=array[j][i+1];
}
}
和
for(int j=0;j<5;j++)
{
for(int i=0;i<5;i++)
{
array[i][j]=array[9-i][j];
}
}
如果有一些优化的功能来复制内存并翻转它们,它们会更好,但我不知道。 对于较大的矩阵,使用多个线程(与核心一样多)将非常有用。有了这个尺寸,我不确定它会有所帮助。
答案 3 :(得分:0)
IVlad的回答略有不同。根据您对填充矩阵的要求,这个带指针的版本允许您改变任何“入门阵列”值,并立即将其反映在八个八分圆中(参见示例)。我在示例中对公式进行了分组,以显示每个八分圆可以水平四种方式反射,垂直四种方式反射,垂直版本是水平的简单转换,切换i
为j
'第
void showArray(int *arr[][8]) {
for (int i = 0; i < 8; ++i){
for (int j = 0; j < 8; ++j)
cout << *arr[i][j] << " ";
cout << endl;
}
}
int main(){
int d[10] = {0,1,2,3,4,5,6,7,8,9};
int n = 8; int *v[8][8]; int k = 0;
for (int i = 0; i < n / 2; ++i){
for (int j = i; j < n / 2; ++j){
v[i][j] = &d[k];
v[j][i] = &d[k];
v[i][n - j - 1] = &d[k];
v[j][n - i - 1] = &d[k];
v[n - i - 1][j] = &d[k];
v[n - j - 1][i] = &d[k];
v[n - i - 1][n - j - 1] = &d[k];
v[n - j - 1][n - i - 1] = &d[k];
k++;
}
}
showArray(v); cout << endl;
d[2] = 44;
showArray(v);
return 0;
}
输出:
0 1 2 3 3 2 1 0
1 4 5 6 6 5 4 1
2 5 7 8 8 7 5 2
3 6 8 9 9 8 6 3
3 6 8 9 9 8 6 3
2 5 7 8 8 7 5 2
1 4 5 6 6 5 4 1
0 1 2 3 3 2 1 0
0 1 44 3 3 44 1 0
1 4 5 6 6 5 4 1
44 5 7 8 8 7 5 44
3 6 8 9 9 8 6 3
3 6 8 9 9 8 6 3
44 5 7 8 8 7 5 44
1 4 5 6 6 5 4 1
0 1 44 3 3 44 1 0