1.螺旋矩阵--从内向外旋转
73 74 75 76 77 78 79 80 8172 43 44 45 46 47 48 49 50
71 42 21 22 23 24 25 26 51
70 41 20 7 8 9 10 27 52
69 40 19 6 1 2 11 28 53
68 39 18 5 4 3 12 29 54
67 38 17 16 15 14 13 30 55
66 37 36 35 34 33 32 31 56
65 64 63 62 61 60 59 58 57
看清以上数字排列的规律,设1点的坐标是(0,0),x方向向右为正,y方向向下为正。例如:7的坐标为(-1,-1),2的坐标为(1,0),3的坐标为(1,1)。编程实现输入任意一点坐标(x,y),输出所对应的数字;或输入任意数字,输出该数字的坐标。
解析:规律能看出来,问题就在于如何利用它。很明显这个队列是顺时针螺旋向外扩展的,我们可以把它看成一层一层往外延伸。第 0 层规定为中间的那个 1,第 1 层为 2 到 9,第 2 层为 10 到 25,注意到 1、9、25、……不就是平方数吗?而且是连续奇数(1、3、5、……)的平方数。这些数还跟层数相关,推算一下就可以知道第 t 层之内一共有 (2t-1)^2 个数,因而第 t 层会从 [(2t-1)^2] + 1 开始继续往外螺旋。给定坐标 (x,y),如何知道该点处于第几层?层数 t = max(|x|,|y|)。
知道了层数,接下来就好办多了,这时我们就知道所求的那点一定在第 t 层这个圈上,顺着往下数就是了。要注意的就是螺旋队列数值增长方向和坐标轴正方向并不一定相同。我们可以分成四种情况——上、下、左、右——或者——东、南、西、北,分别处于四条边上来分析。
东|右:x == t,队列增长方向和 y 轴一致,正东方向(y = 0)数值为 (2t-1)^2 + t,所以 v = (2t-1)^2 + t + y
南|下:y == t,队列增长方向和 x 轴相反,正南方向(x = 0)数值为 (2t-1)^2 + 3t,所以 v = (2t-1)^2 + 3t - x
西|左:x == -t,队列增长方向和 y 轴相反,正西方向(y = 0)数值为 (2t-1)^2 + 5t,所以 v = (2t-1)^2 + 5t - y
北|上:y == -t,队列增长方向和 x 轴一致,正北方向(x = 0)数值为 (2t-1)^2 + 7t,所以 v = (2t-1)^2 + 7t + x
输入任意一点坐标(x,y),输出所对应的数字:
#include"stdafx.h"
#include<iostream>
using namespace std;
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(a) ((a)>0?(a):-(a))
int spiralQueue(int x, int y){
int t = max(abs(x),abs(y));
int s = (2 * t - 1) * (2 * t - 1);
int v;
if(y == -t){
v = s + 7 * t + x;
}else if(y == t){
v = s + 3 * t - x;
}else if(x == -t){
v = s + 5 * t - y;
}else{
v = s + t + y;
}
return v;
}
int main(){
int x,y;
for(y = -2;y <= 2; y++){
for(x = -2; x <= 2; x++){
cout<<spiralQueue(x,y)<<" ";
}
cout<<endl;
}
}
输入任意数字,输出该数字的坐标:
#include"stdafx.h"
#include<iostream>
using namespace std;
void spiralQueue2(int v){
int x,y;
//首先确定所在层数
int t = 0;//层数
int s = 1;
while(v > s){
t++;
s = (2 * t + 1) * (2 * t +1);
}
//确定在哪一条边
int a = v - ((2 * t - 1) * (2 * t -1) + 1);//与第一个数字的差值
if(a <= 2*t-1){//右边
x = t;
y = v - ((2 * t - 1) * (2 * t -1) + t);
}else if(a <= 4*t-1){//下边
x = -(v - ((2 * t - 1) * (2 * t -1) + 3*t));
y = t;
}else if(a <= 6*t-1){//左边
x = -t;
y = -(v - ((2 * t - 1) * (2 * t -1) + 5*t));
}else{//上边
x = v - ((2 * t - 1) * (2 * t -1) + 7*t);
y = -t;
}
cout<<"("<<x<<","<<y<<")"<<endl;
}
int main(){
int v;
while((cin>>v) && (v>0)){
spiralQueue2(v);
}
}
2.螺旋矩阵--从外向内旋转
对m * n 矩阵,最先访问最外层的m * n的矩形上的元素,接着再访问里面一层的 (m - 2) * (n - 2) 矩形上的元素…… 最后可能会剩下一些元素,组成一个点或一条线(见图1)。
对第i个矩形(i=0, 1, 2 …),4个顶点的坐标为:
(i, i) ----------------------------------------- (i, n–1-i)
| |
| |
| |
(m-1-i, i) ----------------------------------------- (m-1-i, n-1-i)
要访问该矩形上的所有元素,只须用4个for循环,每个循环访问一个点和一边条边上的元素即可(见图1)。另外,要注意对最终可能剩下的1 * k 或 k * 1矩阵再做个特殊处理。
按顺时针方向构建一个m * n的螺旋矩阵
矩阵为方阵:
#include"stdafx.h"
#include<iostream>
using namespace std;
void spiralQueue(int n){
//分配空间
int ** a = (int**)malloc(sizeof(int*)*n);
if(a == NULL){
return;
}
int j;
for(j = 0; j < n; j++){
a[j] = (int*)malloc(sizeof(int)*n);
if(a[j] == NULL){
j--;
while(j >= 0){
free(a[j]);
}
free(a);
}
}
int m = 1;
int i;
//分层填充
for(i = 0; i < n/2; i++){
int k = n - i - 1;
//上边
for(j=i;j < k; j++){
a[i][j] = m++;
}
//右边
for(j=i;j < k; j++){
a[j][k] = m++;
}
//下边
for(j=k;j >i; j--){
a[k][j] = m++;
}
//左边
for(j=k;j >i; j--){
a[j][i] = m++;
}
}
if(n % 2 == 1){
a[n/2][n/2] = m;
}
for(i = 0; i < n; i++){
for(j = 0; j < n; j++){
cout<<a[i][j]<<" ";
}
cout<<endl;
}
}
int main(){
int v;
while((cin>>v) && (v>0)){
spiralQueue(v);
}
}
矩阵为m*n矩阵:
#include"stdafx.h"
#include<iostream>
using namespace std;
void spiralQueue(int m,int n){
//分配空间
int ** a = (int**)malloc(sizeof(int*)*m);
if(a == NULL){
return;
}
int j;
for(j = 0; j < m; j++){
a[j] = (int*)malloc(sizeof(int)*n);
if(a[j] == NULL){
j--;
while(j >= 0){
free(a[j]);
}
free(a);
}
}
int v = 1;
int count = m < n ? m : n;
int i;
//分层填充
for(i = 0; i < count/2; i++){
int row = m - i - 1;
int col = n - i - 1;
//上边
for(j=i;j < col; j++){
a[i][j] = v++;
}
//右边
for(j=i;j < row; j++){
a[j][col] = v++;
}
//下边
for(j=col;j >i; j--){
a[row][j] = v++;
}
//左边
for(j=row;j >i; j--){
a[j][i] = v++;
}
}
if(count % 2 == 1){
if(count == m){
int row = m/2;
int col = n - count/2;
for(int k = count/2; k < col; k++){
a[row][k] = v++;
}
}else{
int row = m - count/2;
int col = n/2;
for(int k = count/2; k < row; k++){
a[k][col] = v++;
}
}
}
for(i = 0; i < m; i++){
for(j = 0; j < n; j++){
cout<<a[i][j]<<" ";
}
cout<<endl;
}
}
int main(){
int m,n;
while((cin>>m>>n) && (m>0) && (n>0)){
spiralQueue(m,n);
}
}
在不构造螺旋矩阵的情况下,给定坐标i、j值求其对应的值f(i, j)。