1024 Programmer's Day | C++ NOIP2014 Popularization Group T3 Spiral Matrix

Hello everyone, today I am going to post a serious problem solution.


Portal:

ybt 1967

Luogu p2239


Although this question is the third question in the popularization group, it is actually not too difficult. But, ahem, not for those who like violence .

Take a look at the data scale:

For  50\% the data, 1 \leqslant n \leqslant 100;

For  100\% the data, 1 \leqslant n \leqslant 30,000,1 \leqslant i \leqslant n,1 \leqslant j \leqslant n.

If it is violent, one is that the 900 million array cannot keep up, and the other is O\left ( 900000000 \right )that the time complexity cannot be tolerated.

However, here is a shallow and weak 50%code for one:

#include <iostream>
using namespace std;
int a[105][105];
int main() {
    int n, x, y, m = 1; cin >> n >> x >> y;
    for (int i = 0; i < n / 2 + 1; ++i) {
        for (int j = i; j < n - i; ++j)a[i][j] = m++;
        for (int j = i + 1; j < n - i; ++j)a[j][n - i - 1] = m++;
        for (int j = n - i - 2; j > i; --j)a[n - i - 1][j] = m++;
        for (int j = n - i - 1; j > i; --j)a[j][i] = m++;
    }
    cout << a[x - 1][y - 1] << endl;
}

So, just ask for another way.


This question can be regarded as a recursion, defining a function f(int  n,int  i,int  j), each time the rules are as follows:

If at the outermost layer, let n be the side length, then try to calculate:

On top:return  j;

on the left:return n+i-1;

on the right:return 3*n-2-d+1;

under:return 4*n-4-i+2;

If not, then push one layer inside:

returnf(n-2,i-1,j-1)+4*(n-1);

That is to say, this algorithm needs to be pushed to the level of this matrix at most times , so the time complexity is O(n/2).

Code:

#include<iostream>
using namespace std;
int f(int n, int i, int j) {
    if (i == 1)return j;
    if (j == n)return n + i - 1;
    if (i == n)return 3 * n - 2 - j + 1;
    if (j == 1)return 4 * n - 4 - i + 2;
    return f(n - 2, i - 1, j - 1) + 4 * (n - 1);
}
int main() {
    int n, i, j; cin >> n >> i >> j;
    cout << f(n, i, j) << endl;
}

Me: However, I am still O(n/2)dissatisfied and want to turn it into O\left ( 1 \right )

Audience: How are you, I want to think about the code! Can't do this O\left ( 1 \right )at all!

Me: However, is there any way we can directly determine which ring this number is in and what is the first number of this ring or the last number of the previous ring?

audience:. . .

...

After a long derivation, I figured it out!


The above is a paragraph, and then the analysis will officially begin.

It is relatively simple to find which ring belongs to, just look at the distances of i and j from the edge, respectively. Let the number of layers be f, the expression simplifies to:

f=min(min(i,j),(n+1)-max(i,j))

However, we actually use a judgment statement, so as to find out which of the four directions is up, down, left, and right.

In order to find the first number of this ring, the relational expression must be derived.

(Here, I say a word to my friend: yes, it is the "algebra test" taught by our teacher)

Because the last number of the previous ring is the sum of the perimeters of each layer outside this layer, set m:

m=4(n-1)+4(n-3)+4(n-5)+...+4[n-(2f-3)]

     =4(n-1+n-3+n-5+...+n-2f+3)

     =4\left \{ (f-1)n-[1+(2f-3)]*(f-1)/2\right \}

     =4[(f-1)n-(2f-2)*(f-1)/2]

     =4[(f-1)n-(f-1)(f-1)]

     =4(f-1)(n-f+1)

In this way, we can calculate the four cases according to the above-mentioned points.

Well, here are the ideas, let's write!

Code:

#include<iostream>
using namespace std;
int main() {
	int n, i, j, f, flag, m, ans, c; cin >> n >> i >> j;
	if (min(i, j) < (n + 1) - max(i, j)) {
		if (i < j)flag = 1;
		else flag = 4;
	}
	else {
		if (i > j)flag = 3;
		else flag = 2;
	}
	f = min(min(i, j), (n + 1) - max(i, j));
	m = 4 * (f - 1) * (n - f + 1);
	c = (n - 1) - 2 * (f - 1) + 1;
	i -= f - 1, j -= f - 1;
	if(flag == 1)ans = m + j;
	else if(flag == 2)ans = m + c + i - 1;
	else if(flag == 3)ans = m + 3 * c - j - 1;
	else ans = m + 4 * c - i - 2;
	cout << ans << endl;
	return 0;
}

Well, today I posted a serious problem solution, I think it is very good. Bye-Bye!

Guess you like

Origin blog.csdn.net/qq_43546083/article/details/127455268