螺旋矩阵 之二

 

 

问题

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

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

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

 

 

思路一

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

 

 

由于是 n * n矩阵,对坐标( x y)落在矩形的哪一条边上,可以直接使用 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 & 1 ) return 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的一条边

 

若对第 k k=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)

k k=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

对矩阵的构建和另一种螺旋矩阵类似,可参考 上一篇文章中的 代码 ,下面仅给出给定坐标求值的代码。

 

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" ;

  }

}

 


作者: flyinghearts
出处: http://www.cnblogs.com/flyinghearts/
本文采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议 进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值