1. 程式人生 > >【模擬】[NOIP2014]螺旋矩陣[c++]

【模擬】[NOIP2014]螺旋矩陣[c++]

題目描述

一個n行n列的螺旋矩陣可由如下方法生成:

從矩陣的左上角(第1行第1列)出發,初始時向右移動;如果前方是未曾經過的格子,則繼續前進,否則右轉;重複上述操作直至經過矩陣中所有格子。根據經過順序,在格子中依次填入1, 2, 3, … , n,便構成了一個螺旋矩陣。

下圖是一個n = 4 時的螺旋矩陣。

1 2 3 4

12 13 14 5

11 16 15 6

10 9 8 7

現給出矩陣大小n以及i和j,請你求出該矩陣中第i行第j列的數是多少。

輸入格式:
輸入共一行,包含三個整數 n,i,j,每兩個整數之間用一個空格隔開,分別表示矩陣大小、待求的數所在的行號和列號。

輸出格式:
輸出共一行,包含一個整數,表示相應矩陣中第i行第j列的數。

輸入樣例#1:
4 2 3

輸出樣例#1:
14

【資料說明】
對於50%的資料,1 ≤ n ≤ 100;
對於100%的資料,1 ≤ n ≤ 30,000,1 ≤ i ≤ n,1 ≤ j ≤ n。

思路

我想到的第一種思路是開一個二維陣列,螺旋填入數字,按照座標輸出對應位置的元素。但當n非常大的時候,無法開出相應的二維陣列。然後就想到模擬螺旋填數過程,用兩個變數x,y存當前填數的格子的座標。當x=i,y=j的時候,輸出當前要填的數。
如果一個格子一個格子的去填數字一定會超時,而且在一條直線上直到轉彎前需要填的格子數目是可以通過計算得出的。只要在轉彎處判斷目標格子是否在當前要填的直線段上,在的話就用已經填的格子數目加上目標格子相應座標與當前直線段的端點座標的差,否則加上當前直線段所有要填的格子數目,然後轉彎。

程式碼[c++]
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int main() {
    int n;
    scanf("%d",&n);
    int x,y;
    scanf("%d%d",&x,&y);
    int xx=1,yy=1;
    long long int ans = 1
; int a=n,b=n,c=1,d=1;//相當於劃定邊界 if(n%2==1&&(n+1)/2==x&&(n+1)/2==y)//特判n為奇數且求中心格子 ans=n*n; else { while(1) { if(xx==x&&y>=yy&&y<a) { ans+=(y-yy); break; } else { ans+=(a-yy); yy=a; } a--; if(yy==y&&x>=xx&&x<b) { ans+=(x-xx); break; } else { ans+=(b-xx); xx=b; } b--; if(xx==x&&y<=yy&&y>c) { ans+=(yy-y); break; } else { ans+=(yy-c); yy=c; } c++; if(yy==y&&x<=xx&&x>d) { ans+=(xx-x); break; } else { ans+=(xx-d); xx=d+1; yy=c; } d++; } } printf("%lld\n",ans); return 0; }