사용한 알고리즘
알고리즘 설명
- 몇가지 예외처리를 진행한 뒤, 뒤집기를 진행한다.
Case1. 안 뒤집어도 되는 경우, (1 1), (1 1)로 하나만 뒤집어 끝낸다
Case2. 한번만 뒤집어도 되는 경우, (뒤집을 좌표),(1 1)를 출력
Case3. 두번 뒤집어야 하는 경우, 둘다 출력한다
- 위 알고리즘에서 뒤집는 형태가 앞에서 부터 맞지 않는 부분을 찾아서 풀어나가는 형태와 뒤에서부터 맞지 않는 부분을 찾아서 풀어가는 형태가 있다.
- 두번 뒤집는 경우, 앞에서 부터 뒤집었던 경우 또는 위에서 부터 뒤집는 경우 2가지만 있으므로 이것만 확인하면 된다.
풀이
// baekjoon 2505 yechan
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX_N=10002;
int N, step[MAX_N], s, e, ans[2][2];
int main() {
scanf("%d", &N);
for (int i=1; i<=N; ++i)
scanf("%d", &step[i]);
// 앞에서 부터 어디까지 정렬되어 있는지 확인
s=1;
while (s <= N && step[s] == s) s++;
if (s == N+1) return !printf("1 1\n1 1\n");
// 정렬되지 않은 부분의 숫자가 어디에 있는지 찾아 e에 저장한다.
e=s;
while (step[e] != s) e++;
// 첫번재로 뒤집었던 정보를 저장한다.
ans[0][0] = s, ans[0][1] = e;
// 한번 뒤집어 본다.
reverse(step+s, step+e+1);
// 한번 뒤집었을때 정렬 되어 있다면 출력한다.
s=1;
while (s <= N && step[s] == s) s++;
if (s == N+1) return !printf("%d %d\n1 1\n",
ans[0][0], ans[0][1]);
// 한번 뒤집었을때 매칭되지 않은 부분을 다시 한번 찾는다.
e=s;
while (step[e] != s) e++;
// 두번째 뒤집은 곳을 찾아 저장한다.
ans[1][0] = s, ans[1][1] = e;
// 뒤집어본다.
reverse(step+s, step+e+1);
// 두번 뒤집어 보았을때 정답인지 확인한다.
s=1;
while (s <= N && step[s] == s) s++;
if (s == N+1) return !printf("%d %d\n%d %d\n",ans[0][0],ans[0][1],ans[1][0],ans[1][1]);
// 두번 뒤집어도 정답이 아닌 경우 원래 상태로 돌려 놓는다.
reverse(step+ans[1][0],step+ans[1][1]+1);
reverse(step+ans[0][0],step+ans[0][1]+1);
// 뒤에서 부터 틀린 부분을 찾는다.
e=N;
while (e >= 1 && step[e] == e) e--;
s=e;
while (s >= 1 && step[s] != e) s--;
printf("%d %d\n", s, e);
// 뒤쪽에서 어긋나는 부분을 먼저 뒤집는다.
reverse(step+s, step+e+1);
// 뒤집은 뒤에 같다면 출력한다.
while (e >= 1 && step[e] == e) e--;
if (e == 0) return !printf("1 1\n");
// 같지 않는다면 한번 더 찾는다.
s=e;
while (s >= 1 && step[s] != e) s--;
// 답을 출력한다.
printf("%d %d\n", s, e);
return 0;
}