문제출처:https://www.acmicpc.net/problem/10804
문제
1부터 20까지 숫자가 하나씩 쓰인 20장의 카드가 아래 그림과 같이 오름차순으로 한 줄로 놓여있다. 20장의 카드에 대해 10개의 구간이 주어지면, 주어진 구간의 순서대로 위의 규칙에 따라 순서를 뒤집는 작업을 연속해서 처리한 뒤 마지막 카드들의 배치를 구하는 프로그램을 작성하시오.
조건
총 10개의 줄에 걸쳐 한 줄에 하나씩 10개의 구간이 주어진다. i번째 줄에는 i번째 구간의 시작 위치 ai와 끝 위치 bi가 차례대로 주어진다. 이때 두 값의 범위는 1 ≤ ai ≤ bi ≤ 20이다.
SOL
배열을 뒤집는 아주 좋은 예제 중 하나이다. 배열을 뒤집는 방법은 STL의 reverse 함수를 이용하는 방법도 있고, 직접 구현해서 써도된다.
이정도는 직접 구현을 해보도록 하자. for문을 이용하는 방법도 있고, while문을 이용하는 방법도 있는데 이 예제는 둘의 차이를 잘 보여주는 예제 중 하나인것 같다. 둘 다 구현해보도록 하겠다.
#include <bits/stdc++.h>
using namespace std;
int card[21];
void custom_reverse(int start, int endPoint)
{
for (int i = 0; i < (endPoint - start + 1) / 2; i++)
{
swap(card[start + i], card[endPoint - i]);
}
}
int main()
{
for (int i = 1; i <= 20; i++)
card[i] = i;
for (int i = 1; i <= 10; i++)
{
int start, endPoint;
cin >> start >> endPoint;
custom_reverse(start, endPoint);
}
for (int i = 1; i <= 20; i++)
{
cout << card[i] << " ";
}
return 0;
}
for문에서는 반복하는 횟수
부분인 (endPoint - start+1)/2
이 부분이 이해가 안갈 수 도 있다. 이 부분은 , start,end까지의 배열크기의 중간까지
라는 뜻이다.
예를들어, arr[5]~arr[10]까지면, 5,6,7,8,9,10 으로 6개가 있을거고, 중간지점까지면 반복을 총 3번을 돌아야한다. 따라서, 중간까지의 반복횟수를 구하고 싶으면 위의 식을 주로 쓴다.
위의 식이 기억이 안나면, while로 짜보면 직관적이긴하다. start<=endPoint
즉, 스타트를 하나씩 키우고 endPoint를 하나씩 줄여가면서, start가 endPoint를 넘는 그 지점이 중간지점이 될테니 , 거기까지라는 뜻이다.
#include <bits/stdc++.h>
using namespace std;
int main()
{
int card[21];
int start, endPoint;
for (int i = 1; i < 21; i++)
{
card[i] = i;
}
for (int i = 0; i < 10; i++)
{
cin >> start >> endPoint;
while (start <= endPoint)
{
swap(card[start], card[endPoint]);
start++;
endPoint--;
}
}
for (int i = 1; i < 21; i++)
cout << card[i] << " ";
return 0;
}
for은 횟수를 정량적으로 나타낼 수 있을 때 유리한 반복문이고, while은 조건으로 반복횟수를 나타낼 수 있을 때, 유리하다. while과 for은 둘 다 서로 바꿔서 쓸 수 있기 때문에 ,사실 취향에 맞는거 쓰면된다.