본문 바로가기
Algorithm/BOJ

[BOJ]17406번: 배열 돌리기 4 (c++)

by HBGB 2020. 9. 4.

www.acmicpc.net/problem/17406

 

17406번: 배열 돌리기 4

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

www.acmicpc.net

 

구현 + 브루트포스

//https://www.acmicpc.net/problem/17406
#include <iostream>
#include <vector>
#include <algorithm>
#include <limits>

using namespace std;

template <typename T>
using d_vector = vector<vector<T>>;

// r, c : 회전하는 사각형의 가장 왼쪽 윗칸
struct rtt_info 
{
	int r, c, s;
};

int get_min_sum_array(d_vector<int> &A)
{
	int min_sum = numeric_limits<int>::max();
	for (int i = 0; i < A.size(); ++i)
	{
		int sum = 0;
		for (int j = 0; j < A[i].size(); ++j)
		{
			sum += A[i][j];
		}
		min_sum = min(sum, min_sum);
	}
	return min_sum;
}

void inline swap(int &val1, int &val2)
{
	int tmp = val1;
	val1 = val2;
	val2 = tmp;
}

void move_val(d_vector<int>& A, rtt_info info)
{
	int len = info.s * 2;
	int bf_val = A[info.r][info.c];

	// 윗변을 오른쪽으로 한칸씩 이동
	for (int i = 0; i < len; ++i)
	{
		swap(A[info.r][++info.c], bf_val);
	}
	// 우변을 아래쪽으로 한칸씩 이동
	for (int i = 0; i < len; ++i)
	{
		swap(A[++info.r][info.c], bf_val);
	}
	// 밑변을 왼쪽으로 한칸씩 이동
	for (int i = 0; i < len; ++i)
	{
		swap(A[info.r][--info.c], bf_val);
	}
	// 좌변을 위쪽으로 한칸씩 이동
	for (int i = 0; i < len; ++i)
	{
		swap(A[--info.r][info.c], bf_val);
	}
}

void rotate(d_vector<int>& A, rtt_info info)
{
	// info.s > 0 일 동안 회전
	while (info.s)
	{
		// 네 변의 값들을 한칸씩 이동
		move_val(A, info);

		// (더 작은) 다음 회전사각형 준비
		++info.r;
		++info.c;
		--info.s;
	}
}

int get_min_sum_rotated_2d_vector(d_vector<int> A, vector<rtt_info> &infos, vector<int> &order)
{
	// 배열 A회전 : order순서에 따른 info값 대로
	for (int idx : order)
	{
		rotate(A, infos[idx]);
	}
	
	// 회전 후 배열 A의 최솟값 반환
	return get_min_sum_array(A);
}

int main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	// 입력
	int N, M, K;
	cin >> N >> M >> K;
	d_vector<int> A(N, vector<int>(M));
	for (int i = 0; i < N; ++i)
	{
		for (int j = 0; j < M; ++j)
		{
			cin >> A[i][j];
		}
	}
	vector<rtt_info> infos(K);
	for (int i = 0; i < K; ++i)
	{
		int R, C, S;
		cin >> R >> C >> S;

		infos[i].r = R - S - 1;
		infos[i].c = C - S - 1;
		infos[i].s = S;
	}

	// 순열을 위한 order배열 생성
	vector<int> order(K);
	for (int i = 0; i < K; ++i)
	{
		order[i] = i;
	}
	
	// infos 순열대로 배열A를 회전시키고 최솟값 구하기
	int min_val = numeric_limits<int>::max();
	do {
		
		int val = get_min_sum_rotated_2d_vector(A, infos, order);
		min_val = min(min_val, val);

	} while (next_permutation(order.begin(), order.end()));

	// 출력
	cout << min_val;

	return 0;
}

 

이 문제는 구현적 성격이 강했다.

 

TIP_순열

배열 A와 사용 가능한 회전 연산이 주어졌을 때, 배열 A의 값의 최솟값을 구해보자.
회전 연산은 모두 한 번씩 사용해야 하며, 순서는 임의로 정해도 된다.
1 ≤ K ≤ 6

 

회전의 순서에 따라 값이 달라지고, 그 값들의 최솟값을 구해야 한다.

이때 회전 정보의 개수가 K로 주어지는데, 이 값의 크기가 매우 작다.

따라서 순열로 하나하나 값을 구해서 크기를 비교하는 것이 적절하다.

 

 

 

TIP_회전

과정을 하나씩 쪼개서 생각하는게 좋다.

 

1. vector<info> infos 순서대로 회전

// 배열 A회전 : order순서에 따른 info값 대로
for (int idx : order)
{
	rotate(A, infos[idx]);
}

 

2. 한 사각형에는 info.s 크기만큼 내부 사각형이 있다.

내부 사각형들의 시작점은 우하향한다. 

// info.s > 0 일 동안 회전
while (info.s)
{
	// 네 변의 값들을 한칸씩 이동
	move_val(A, info);

	// (더 작은) 다음 회전사각형 준비
	++info.r;
	++info.c;
	--info.s;
}

 

3. 4변의 값을 한칸씩 이동.

이전 칸의 값을 bf_val 변수를 두어서 다음 이동으로 넘긴다.

int len = info.s * 2;
int bf_val = A[info.r][info.c];

// 윗변을 오른쪽으로 한칸씩 이동
for (int i = 0; i < len; ++i)
{
	swap(A[info.r][++info.c], bf_val);
}

...

 

 

 

'Algorithm > BOJ' 카테고리의 다른 글

[BOJ]11060번: 점프 점프 (c++)  (0) 2020.09.11
[BOJ]16916번: 부분 문자열 (c++)  (0) 2020.09.05
[BOJ]9935번: 문자열 폭발(c++)  (0) 2020.09.04
[BOJ]11048번: 이동하기 (c++)  (0) 2020.09.03
[BOJ]16968번: 차량 번호판 1 (c++)  (0) 2020.07.17

댓글