1024 Programmierertag | C++ NOIP2014 Popularization Group T3 Spiral Matrix

Hallo zusammen, heute werde ich eine ernsthafte Problemlösung posten.


Portal:

jbt 1967

Luogu p2239


Obwohl diese Frage die dritte Frage in der Popularisierungsgruppe ist, ist sie eigentlich nicht allzu schwierig. Aber, ähm, nichts für diejenigen, die Gewalt mögen .

Schauen Sie sich die Datenskala an:

Für  50\% die Daten, 1 \leqslant n \leqslant 100;

Für  100\% die Daten, 1 \leqslant n \leqslant 30.000,1 \leqslant i \leqslant n,1 \leqslant j \leqslant n.

Wenn es gewalttätig ist, kann das 900-Millionen-Array zum einen nicht mithalten, und zum anderen O\links ( 900000000 \rechts )kann die Zeitkomplexität nicht toleriert werden.

Hier ist jedoch ein flacher und schwacher 50%Code für einen:

#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;
}

Fragen Sie also einfach nach einem anderen Weg.


Diese Frage kann als Rekursion betrachtet werden, die eine Funktion definiert f(int  n,int  ich, int  j), wobei die Regeln jeweils wie folgt lauten:

Wenn in der äußersten Schicht n die Seitenlänge ist, dann versuchen Sie zu berechnen:

Oben drauf:Rückkehr  j;

auf der Linken:Rückkehr n+i-1;

auf der rechten Seite:Rückkehr 3*n-2-d+1;

unter:Rückkehr 4*n-4-i+2;

Wenn nicht, dann schieben Sie eine Schicht hinein:

Rückkehrf(n-2,i-1,j-1)+4*(n-1);

Das heißt, dieser Algorithmus muss zu den meisten Zeiten auf das Niveau dieser Matrix gebracht werden, also ist die Zeitkomplexität 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;
}

Ich: Ich bin aber immer noch O(n/2)unzufrieden und möchte es ändern O\links ( 1 \rechts )

Publikum: Wie geht es dir, ich möchte über den Code nachdenken! Kann das gar nicht O\links ( 1 \rechts )!

Ich: Gibt es jedoch eine Möglichkeit, direkt zu bestimmen, in welchem ​​Ring sich diese Nummer befindet und wie lautet die erste Nummer dieses Rings oder die letzte Nummer des vorherigen Rings?

Publikum:. . .

...

Nach langem Hin und Her habe ich es herausgefunden!


Das Obige ist ein Absatz, und dann beginnt die Analyse offiziell.

Es ist relativ einfach herauszufinden, zu welchem ​​Ring er gehört, man schaue sich nur die Abstände von i bzw. j von der Kante an. Die Anzahl der Schichten sei f, der Ausdruck vereinfacht sich zu:

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

Tatsächlich verwenden wir jedoch die Urteilsaussage, um herauszufinden, welche der vier Richtungen oben, unten, links und rechts ist.

Um die erste Zahl dieses Rings zu finden, muss der Vergleichsausdruck hergeleitet werden.

(Hier sage ich ein Wort zu meinem Freund: Ja, es ist der "Algebra-Test", der von unserem Lehrer unterrichtet wird)

Da die letzte Zahl des vorherigen Rings die Summe der Umfänge jeder Schicht außerhalb dieser Schicht ist, setzen Sie 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\links \{ (f-1)n-[1+(2f-3)]*(f-1)/2\rechts \}

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

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

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

Auf diese Weise können wir die vier Fälle nach den oben genannten Punkten berechnen.

Nun, hier sind die Ideen, schreiben wir!

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

Nun, heute habe ich eine ernsthafte Problemlösung gepostet, ich finde sie sehr gut. Tschüss!

Je suppose que tu aimes

Origine blog.csdn.net/qq_43546083/article/details/127455268
conseillé
Classement