所有七种方式反映方形矩阵八分圆的算法

时间:2015-06-01 14:04:04

标签: java c arrays algorithm matrix

在偶数维s的方阵中,有s/4(s/2+1)种类型的正方形,可以在矩阵周围以七种不同的方式反映出来。例如,10 x 10矩阵在下图中具有独特的正方形颜色:

octant

这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个键值。此外,我尝试的循环可能不是最快的方法。

4 个答案:

答案 0 :(得分:4)

假设这是你的意思:

enter image description here

考虑到左上角的黑色区域,我们只需迭代该区域中的所有元素(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的回答略有不同。根据您对填充矩阵的要求,这个带指针的版本允许您改变任何“入门阵列”值,并立即将其反映在八个八分圆中(参见示例)。我在示例中对公式进行了分组,以显示每个八分圆可以水平四种方式反射,垂直四种方式反射,垂直版本是水平的简单转换,切换ij'第

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