티스토리 뷰

공부/PS

[BOJ] 17406: 배열 돌리기 4

복소평면 2020. 7. 6. 00:58

https://www.acmicpc.net/problem/17406

 

17406번: 배열 돌리기 4

크기가 N×M 크기인 배열 A가 있을때, 배열 A의 값은 각 행에 있는 모든 수의 합 중 최솟값을 의미한다. 배열 A가 아래와 같은 경우 1행의 합은 6, 2행의 합은 4, 3행의 합은 15이다. 따라서, 배열 A의

www.acmicpc.net

 

말 그대로 배열을 돌린다.

가능한 회전 연산의 수는 최대 6가지이니 O(K!)에서 6! = 720

회전은 구현하기는 복잡해 보여도 시간 복잡도가 크진 않으니 무식한 방법으로 1초 안에 풀 수 있겠다.

 

 

배열 자체를 복사해도 딱히 타임아웃이 나지는 않는다.

값 형식으로 전달하면 코드도 깔끔해지고 어차피 배열을 다시 바꾸려면 벡터를 만들어야 하기에 그 방법으로 바꿨다.

 

K의 값이 최대 6인 만큼 무식하게 풀어도 상관 없기에

배열의 회전을 구현하는 것이 관건인 문제다.

 

 

다음과 같은 배열에 (3, 4, 2)연산을 적용하려고 할 때, 중심은 당연 3행 4열인 A[3][4](실제 코드에서는 A[2][3])이 될 것이다. 이 중심은 움직이지 않는다.

 

그림을 통해 회전 연산을 할 배열은 한 변의 길이가 2 * s + 1인 정사각형의 모습을 한다는 것을 알 수 있다.

 

for (int ns = 1; ns <= s; ++ns) {
		std::vector<int> group;
		for (int nr = r - ns, nc = c - ns; nc < c + ns; ++nc) {
			group.push_back(a[nr][nc]);
		}
		for (int nr = r - ns, nc = c + ns; nr < r + ns; ++nr) {
			group.push_back(a[nr][nc]);
		}
		for (int nr = r + ns, nc = c + ns; nc > c - ns; --nc) {
			group.push_back(a[nr][nc]);
		}
		for (int nr = r + ns, nc = c - ns; nr > r - ns; --nr) {
			group.push_back(a[nr][nc]);
		}
		groups.push_back(group);
	}

 

그리고 먼저, 1부터 s까지 증가하는 변수 ns를 만든다.

회전 연산을 적용해야 할 요소들은 각각 [2 * 1 + 1, 2 * s +1]의 범위를 갖는 정사각형의 테두리로 나타내진다.

 

반복문을 통해 정사각형의 가장자리만 저장한다.

 

1 2 3

8 9 4

7 6 5

 

와 같은 형태의 배열이였다면, { 1, 2, 3, 4, 5, 6, 7, 8 }으로 벡터에 저장되었을 것이다.

 

for (int ns = 1; ns <= s; ++ns) {
    auto& group = groups[ns - 1];
    std::rotate(group.rbegin(), group.rbegin() + 1, group.rend());
    // ...
}

 

여기에 각각 rotate 함수를 사용한다.

rotate 함수에 대해선 라이님 블로그에 잘 정리되어 있다 (kks227.blog.me/220246910224)

 

[C++ 강좌] 095 - 알고리즘 헤더 파일 (4) - reverse(), rotate(), random_shuffle()

이번 글 역시 구간에 대한 함수들입니다.역시 함수 이름을 참 잘 지어놔서, 이름으로 기능을 추론하기 쉽습...

blog.naver.com

for (int ns = 1; ns <= s; ++ns) {
    // rotate 연산 적용 ...
    
    int len = group.size();
    int index = 0;
    for (int nr = r - ns, nc = c - ns; nc < c + ns; ++nc) {
        a[nr][nc] = group[index++];
    }
    for (int nr = r - ns, nc = c + ns; nr < r + ns; ++nr) {
        a[nr][nc] = group[index++];
    }
    for (int nr = r + ns, nc = c + ns; nc > c - ns; --nc) {
        a[nr][nc] = group[index++];
    }
    for (int nr = r + ns, nc = c - ns; nr > r - ns; --nr) {
        a[nr][nc] = group[index++];
    }
}

 

위 벡터에 rotate 연산을 적용한 결과는 다음과 같을 것이다.

{ 8, 1, 2, 3, 4, 5, 6, 7 }

 

이제 이 바뀐 값을 아까 정사각형의 가장자리에 넣어 주면 끝이다.

 

8 1 2

7 9 3

6 5 4

 

배열을 성공적으로 회전시켰다.

ns가 증가하며 다른 정사각형들에도 똑같이 연산이 적용 될 것이다.

 

#include <iostream>
#include <tuple>
#include <vector>
#include <algorithm>

int N, M, K;
std::vector<std::vector<int>> A;

int getMinValue(std::vector<std::vector<int>>& a) {
	int ret = 10e8;
	for (int i = 0; i < N; ++i) {
		int sum = 0;
		for (int j = 0; j < M; ++j) {
			sum += a[i][j];
		}
		ret = std::min(ret, sum);
	}
	return ret;
}

void solve(std::vector<std::vector<int>>& a, std::tuple<int, int, int> t) {
	int r, c, s;
	std::tie(r, c, s) = t;
	std::vector<std::vector<int>> groups;
	for (int ns = 1; ns <= s; ++ns) {
		std::vector<int> group;
		for (int nr = r - ns, nc = c - ns; nc < c + ns; ++nc) {
			group.push_back(a[nr][nc]);
		}
		for (int nr = r - ns, nc = c + ns; nr < r + ns; ++nr) {
			group.push_back(a[nr][nc]);
		}
		for (int nr = r + ns, nc = c + ns; nc > c - ns; --nc) {
			group.push_back(a[nr][nc]);
		}
		for (int nr = r + ns, nc = c - ns; nr > r - ns; --nr) {
			group.push_back(a[nr][nc]);
		}
		groups.push_back(group);
	}
	for (int ns = 1; ns <= s; ++ns) {
		auto& group = groups[ns - 1];
		std::rotate(group.rbegin(), group.rbegin() + 1, group.rend());
		int len = group.size();
		int index = 0;
		for (int nr = r - ns, nc = c - ns; nc < c + ns; ++nc) {
			a[nr][nc] = group[index++];
		}
		for (int nr = r - ns, nc = c + ns; nr < r + ns; ++nr) {
			a[nr][nc] = group[index++];
		}
		for (int nr = r + ns, nc = c + ns; nc > c - ns; --nc) {
			a[nr][nc] = group[index++];
		}
		for (int nr = r + ns, nc = c - ns; nr > r - ns; --nr) {
			a[nr][nc] = group[index++];
		}
	}
}

int main() {
	std::cin >> N >> M >> K;
	A.resize(N);
	for (int i = 0; i < N; ++i) {
		A[i].resize(M);
		for (int j = 0; j < M; ++j) {
			std::cin >> A[i][j];
		}
	}

	std::vector<std::tuple<int, int, int>> rotateVec;
	for (int i = 0; i < K; ++i) {
		int r, c, s;
		std::cin >> r >> c >> s;
		--r; --c;
		rotateVec.push_back({ r, c, s });
	}
	std::sort(rotateVec.begin(), rotateVec.end());
	int ret = 10e8;
	do {
		auto a = A;
		for (const auto& tuple : rotateVec) {
			solve(a, tuple);
		}
		ret = std::min(ret, getMinValue(a));
	} while (std::next_permutation(rotateVec.begin(), rotateVec.end()));
	std::cout << ret;

	return 0;
}

'공부 > PS' 카테고리의 다른 글

[BOJ] 4902: 삼각형의 값  (0) 2020.07.11
[BOJ] 16988: Baaaaaaaaaduk2 (Easy)  (0) 2020.07.09
[BOJ] 15686: 치킨 배달  (0) 2020.07.05
[BOJ] 17088: 등차수열 변환  (0) 2020.07.05
[BOJ] 15683: 감시  (0) 2020.07.04
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함