컴퓨터 사이언스/1고리즘

백준 17406 : 배열 돌리기 4

저세상 개발자 2021. 7. 23. 01:38

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

 

17406번: 배열 돌리기 4

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

www.acmicpc.net

 

주어지는 입력에 따라 배열의 부분 행렬에 대하여 시계 방향으로 한 칸씩 이동시키는 문제이다. 이전에 포스팅한 배열 돌리기 1과 유사한 매커니즘인데, 방향이 반대이고 부분 행렬을 회전시킨다는 차이점이 있다.

(이전 문제 풀이 참고 링크 -https://unfunhy.tistory.com/50)

 

백준 16926 : 배열 돌리기 1

https://www.acmicpc.net/problem/16926 16926번: 배열 돌리기 1 크기가 N×M인 배열이 있을 때, 배열을 돌려보려고 한다. 배열은 다음과 같이 반시계 방향으로 돌려야 한다. A[1][1] ← A[1][2] ← A[1][3] ← A[..

unfunhy.tistory.com

 

케이스를 나누는 핵심 방법은 이전 문제와 동일한 방법을 사용했고, 이번 문제는 주어지는 커맨드들의 순서를 잘 조합해서 행의 합이 가장 작은 경우를 찾는 문제라 백트래킹 방법으로 문제를 해결했다.

 

#include <iostream>

#define min(a,b) a<b?a:b
using namespace std;

struct CMD {
	int x, y, offset;
};

int n, m, k;
int min_val = 5e3;
int board[50][50];
bool used_cmd[6];
CMD cmd[6];

void move(int& curx, int& cury, bool undo, int sx, int sy, int ex, int ey) {
	if (!undo) {
		if (cury == sy && curx != sx) --curx;
		else if (curx == ex && cury != sy) --cury;
		else if (cury == ey && curx != ex) ++curx;
		else if (curx == sx && cury != ey) ++cury;
	}
	else {
		if (cury == sy && curx != ex) ++curx;
		else if (curx == ex && cury != ey) ++cury;
		else if (cury == ey && curx != sx) --curx;
		else if (curx == sx && cury != sy) --cury;
	}
}

void rotate(int sx, int sy, int ex, int ey, bool undo=false) {
	//기저 조건
	if (ex - sx < 2) return;

	int curx, cury, nx, ny, tmp;
	
	if (!undo) curx = sx, cury = sy + 1;
	else curx = sx + 1, cury = sy;

	tmp = board[cury][curx];
	while (!(curx == sx && cury == sy)) {
		nx = curx, ny = cury;
		move(curx, cury, undo, sx, sy, ex, ey);
		board[ny][nx] = board[cury][curx];
	}
	board[sy][sx] = tmp;

	++sx, ++sy, --ex, --ey;
	rotate(sx, sy, ex, ey, undo);
}

void dfs(int lvl) {
	//기저 조건
	if (lvl >= k) {
		for (int y = 0; y < n; y++) {
			int sum = 0;
			for (int x = 0; x < m; x++) {
				sum += board[y][x];
			}
			min_val = min(min_val, sum);
		}
		return;
	}

	int curx, cury, offset;
	int sx, sy, ex, ey;

	for (int i = 0; i < k; i++) {
		if (used_cmd[i]) continue;

		cury = cmd[i].y - 1;
		curx = cmd[i].x - 1;
		offset = cmd[i].offset;
		
        //회전 영역 바운더리 설정
		sx = curx - offset; if (sx < 0) sx = 0;
		sy = cury - offset; if (sy < 0) sy = 0;
		ex = curx + offset; if (ex >= m) ex = m - 1;
		ey = cury + offset; if (ey >= n) ey = n - 1;
		
        //백트래킹
		rotate(sx, sy, ex, ey);
		used_cmd[i] = 1;

		dfs(lvl + 1);
		
        //undo, 반대 방향으로 회전
		rotate(sx, sy, ex, ey, 1);
		used_cmd[i] = 0;
	}
}

int main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	
    //input
	cin >> n >> m >> k;
	for (int y = 0; y < n; y++) {
		for (int x = 0; x < m; x++) {
			cin >> board[y][x];
		}
	}
	for (int i = 0; i < k; i++) {
		cin >> cmd[i].y >> cmd[i].x >> cmd[i].offset;
	}

	//solution
	dfs(0);
	cout << min_val;

	return 0;
}
메모리: 2040 kb 시간: 16 ms