螺旋矩阵 之二

问题

1 按顺时针方向构建(或螺旋访问)一个n * n的螺旋矩阵,效果见下图。

2 在不构造螺旋矩阵的情况下,给定坐标ij值求其对应的值f(i, j)

比如对6 * 6矩阵, f(2, 0) =19  f(2, 1) = 6

 


思路一

一篇文章已经讨论了一类螺旋矩阵(由外向内),而这一类螺旋矩阵,则是由内向外扩散。这两类矩阵可以通过下面的方法相互转换。

 


由于是 n * n矩阵,对坐标(xy)落在矩形的哪一条边上,可以直接使用x <= y进行判断,原来的代码可以优化为:

 

int getv(int x, int y, int n) // 由外内向顺时针螺旋
{
  
if (x <= y) {
    
int k = min(x, n - 1 - y);
    
return  4 * k * (n - k) + 1 + (x + y - k * 2);
  }
  
int k = min(y, n - 1 - x) + 1
  
return 4 * k * (n - k) + 1 - (x + y - (k - 1* 2);
}

int getv_in(int x, int y, int n) // 由内向外顺时针螺旋
{
  
if (n & 1return n * n + 1 - getv(x, n - 1 - y, n);
  
return n * n + 1 - getv(n - 1 - x, y, n);
}


 

 

思路二

  将矩阵按1,1,2,2, … n-1,n-1, n 个数划分成几个矩形,比如:7*7矩阵(参考图1):

    1 2 3 4 5 6 6个点构成矩形0

    7 8 9 10 11 12 13 14 15 16)(17 18 19 20 构成矩形

   21 22 23 24 25)(26 27 28 29 30)(31 32 33 34 35 36)(37 38 39 40 41 42)构成矩形2

   43 44 45 46 47 48 49 构成矩形3的一条边

 

若对第kk=0, 1, 2 …)个矩形,起始点坐标为(i, i),则 i + k = floor((n-1)/2)

其右上角顶点坐标为(i, i + 2 * k + 1

t = 2 * floor((n-1)/2) + 1 = (n - 1) | 1 则右上角顶点坐标为:(i, t - i)

kk=0, 1, 2 …)个矩阵的4个顶点为(注意起始点不是左上角顶点而是(i, i)):

(i, i-1) ----------------------------------------- (i, t-i)

|                                                    |

|                                                    |

|                                                    |

(t-i, i-1) ----------------------------------------- (t-i, t-i) 

 

对给定的坐标(x,y),如果它落在某个这类矩形上,显然其所在的矩形起始点横坐标i满足:

i = min{x, y+1, t-x, t-y}

第k个矩形内的所有点构成(2*k+2)*(2*k+3)矩阵,共有元素P(k)=(2*k+2)*(2*k+3),第k个矩形的起始点(i,i)对应的值为

T(i)=P(k-1)+1=2*k*(2*k+1)+1=(t-2*i)*(t-2*i-1)+1

 

对某个矩形,设矩形上的点(x, y)到起始点(i,i)的距离d = x-i + y-i = x+y-2*i,设点(x, y)到下一起始点(i-1,i-1)的距离为dd,则 dd = d + 2

① 向右和向下都只是横坐标或纵坐标增加1,这两条边上的点满足f(x, y) = T(i) + d

② 向左和向下都只是横坐标或纵坐标减少1,这两条边上的点满足f(x, y) = T(i-1) –dd

对矩阵的构建和另一种螺旋矩阵类似,可参考上一篇文章中的代码

 

构建矩阵代码:

代码
//www.cnblogs.com/flyinghearts
#include<cstdio>
const int N = 128;
int a[N][N];

void set_1a(int n)
{
  
const int nn = (n - 1| 1;
  
int x = nn / 2u, y = x, k = 0;
  
for (int len = 1; len < nn; len += 2) {
    
for (int j = 0; j < len; ++j) a[x][y++= ++k;
    
for (int j = 0; j < len; ++j) a[x++][y] = ++k;
    
for (int j = 0; j <= len; ++j) a[x][y--= ++k;
    
for (int j = 0; j <= len; ++j) a[x--][y] = ++k;
  }
  
  
for(int j = 0; j < nn; ++j) a[0][j] = ++k;
  
if ((n & 1== 0) {
    
for (int j = 0; j < nn; ++j) a[j][nn] = ++k;
    
for (int j = nn; j >= 0--j) a[nn][j] = ++k;  
  }
}

void set_1b(int n)
{
  
int len = 0, k = 0, x = (n - 1/ 2u, y = x;
  
while (1) {
    
++len;
    
for (int j = 0; j < len; ++j) a[x][y++= ++k;
    
if (len == n) break;
    
for (int j = 0; j < len; ++j) a[x++][y] = ++k;

    
++len;
    
for (int j = 0; j < len; ++j) a[x][y--= ++k;
    
if (len == n) break;
    
for (int j = 0; j < len; ++j) a[x--][y] = ++k;    
  }
}

void set_2(int n)
{
  
const int nn = (n - 1| 1;
  
int k = 0;
  
for (int i = nn / 2u; i > 0--i) {
    
const int C = nn - i;
    
for (int j = i; j < C; ++j) a[i][j] = ++k;    
    
for (int j = i; j < C; ++j) a[j][C] = ++k;    
    
for (int j = C; j >= i; --j) a[C][j] = ++k;    
    
for (int j = C; j >= i; --j) a[j][i - 1= ++k;
  }
  
  
for(int j = 0; j < nn; ++j) a[0][j] = ++k;
  
if ((n & 1== 0) {
    
for (int j = 0; j < nn; ++j) a[j][nn] = ++k;
    
for (int j = nn; j >= 0--j) a[nn][j] = ++k;  
  }
}


void print(int n)
{
  
for (int i = 0; i < n; ++i) {
    
for (int j = 0; j < n; ++j)
      printf(
"%3d ",a[i][j]);
    printf(
"\n");
  } 
    printf(
"\n");  
}

int main()
{
  
for (int i = 3; i < 9++i) {
    set_1b(i);
    print(i);
  }
}


 

给定坐标求值的代码:

int getv(int x, int y, int n) //螺旋矩阵(由内向外扩散)
{
  
int t = (n - 1| 1;
  
if (x <= y) {
    
int k = min(x, t - y);
    
return (t - 2 * k) * (t - 2 * k - 1+ 1 + (x + y - 2 * k);
  }
  
int k = min(y + 1, t - x) - 1;
  
return (t - 2 * k) * (t - 2 * k - 1+ 1 - (x + y - 2 * k);
}


完整测试代码:

代码
//螺旋矩阵(由内向外扩散),给定坐标直接求值 by flyinghearts
//www.cnblogs.com/flyinghearts
#include<iostream>
#include
<algorithm>
using std::min;
using std::cout;
 
int getv(int x, int y, int n) //螺旋矩阵(由内向外扩散)
{
 
int t = (n - 1| 1;
  
if (x <= y) {
    
int k = min(x, t - y);
    
return (t - 2 * k) * (t - 2 * k - 1+ 1 + (x + y - 2 * k);
  }
  
int k = min(y + 1, t - x) - 1;
  
return (t - 2 * k) * (t - 2 * k - 1+ 1 - (x + y - 2 * k);
}
 
 
int main()
{
  
const int M = 12;
  
for (int k = 2; k < M; ++k) {
    
for (int i = 0; i < k; ++i) {
      
for (int j = 0; j < k; ++j) {
        cout.width(
4);
        cout 
<< getv(i, j, k) << " ";
      }
      cout 
<< "\n"
    }
    cout 
<< "\n";
  }
}


 

posted @ 2010-12-25 10:53  flyinghearts  阅读(4104)  评论(6编辑  收藏  举报