반응형

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

 

14503번: 로봇 청소기

첫째 줄에 방의 크기 $N$과 $M$이 입력된다. $(3 \le N, M \le 50)$  둘째 줄에 처음에 로봇 청소기가 있는 칸의 좌표 $(r, c)$와 처음에 로봇 청소기가 바라보는 방향 $d$가 입력된다. $d$가 $0$인 경우 북쪽

www.acmicpc.net

 

 

 

💡 로봇 청소기

 

 

 

✅ 문제 풀이
문제를 풀기 전에 지문을 완벽하게 해석해야 한다. 질문게시판을 보면 알겠지만, 문제 해석에 어려움이 많아보인다.

 

  • 로봇청소기는 입력으로 주어지는 (r,c)에서 출발하고 방향도 입력으로 주어지는 d를 향하여 시작한다.
  • 이때 d는 북쪽일 경우 0, 동쪽일 경우 1, 남쪽일 경우 2, 서쪽일 경우 3이다.
    나는 여기서 동쪽과 서쪽을 반대로 생각하는 실수로 인해 자꾸 틀렸습니다가 떠서 알고리즘의 문제인가 싶었다..
  • 방의 상태는 2차원 arr벡터에, 청소를 한 칸의 횟수는 count에 저장한다.
  • 그리고 다음 과정을 while문을 통해서 반복해주면 된다.
  1. 현재 칸이 청소가 안되어 있으면, 즉 0이면 count를 하나 증가시켜주고 현재 칸의 값을 2로 바꾸어준다.
    2로 하는 이유는 청소가 안된 0과 벽인 1을 구분하기 위함이다.
  2. 그리고 현재 칸에서 동서남북에 있는 칸 중 청소가 안된 칸이 있는지 확인한다. 이때 어디가 청소가 안된 칸인지 정확히 알 필요는 없다. 그냥 청소가 안된 칸이 있다면 bool타입의 clean을 false로 바꾸어주면 된다.
  3. 만약(if) 현재 칸에서 동서남북에 있는 칸 중 청소가 안된 칸이 없다면 clean이 true일 것이다. 따라서 clean이 true이면 다음을 따른다.
    3-A. 만약(if) 현재 방향에서 한칸 뒤가 벽이 아니라면, 즉 1이 아니라면 후진할 수 있는 것이기 때문에 r과 c를 한칸 후진한 좌표로 갱신해준다. 이 로직을 수행하고 나면 다시 while문의 1번으로 돌아가게 될 것이다.
    3-B. 만약 현재 방향에서 한칸 뒤가 벽이라면(else), 즉 1이라면 현재 상태에서 청소를 멈춘다. 따라서 count를 출력하고 return 0;을 함으로써 while문을 끝내고 프로그램을 종료한다.
  4.  3과 같지 않다면(else), 즉 주변에 청소할 칸이 하나라도 있으면 clean이 false일 것이다. 따라서 clean이 false이면 다음을 따른다. 
    4-A. 무조건 현재 방향에서 왼쪽(반시계방향)으로 90도 돌린다. 즉 현재 방향이 북이라면 서로, 서라면 남으로, 남이라면 동으로, 동이라면 북으로 돌아간다. 따라서 숫자로 보면 0>>3>>2>>1>>0...방향이다.
    이는 (d+3)을 4로 나눈 나머지와 같아진다. 따라서 d를 (d+3)%4로 갱신해 주면 된다.
    4-B. 그리고 갱신된 방향으로 한칸 앞이 청소가 안되어 있으면 r과 c를 한칸 앞인 좌표로 갱신해준다. 이 로직을 수행하고 나면 다시 while문의 1번으로 돌아가게 될 것이다.
  5. while문을 끝내고 난 뒤에는 count를 출력하도록 한다. 

 

 

✏ 코드 전문
#include<iostream>
#include<vector>

using namespace std;

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

	int n, m;
	cin >> n >> m;
	int r, c, d;
	cin >> r >> c >> d;

	vector<vector<int>> arr(n, vector<int> (m));
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cin >> arr[i][j];
		}
	}

	int count = 0;

	int dx[] = { -1,1,0,0 };
	int dy[] = { 0,0,-1,1 };

	while (1) {
		if (arr[r][c] == 0) {//현재 위치가 벽이 아니고, 청소가 안된 곳이라면
			count++;
			arr[r][c] = 2;//청소를 완료하면 2로 채운다
		}
		
		bool clean = true;

		for (int i = 0; i < 4; i++) {
			int x = r + dx[i];
			int y = c + dy[i];
			
			if (arr[x][y] == 0) {
				clean = false;//하나라도 청소안된 곳이있으면 바로 빠져나옴
				break;
			}
			
		}
		if (clean) {//주변에 청소할데가 없으면
			int bx, by;
			if (d == 0) {//북
				bx = r + 1;
				by = c;
			}
			else if (d == 1) {//동
				bx = r;
				by = c - 1;
			}
			else if (d == 2) {//남
				bx = r - 1;
				by = c;
			}
			else {//서
				bx = r;
				by = c + 1;
			}

			if (arr[bx][by] != 1) {//후진할 수 있으면
				r = bx;
				c = by;
			}
			else {
				cout << count;
				return 0;//중단
			}
		}
		//0>>3>>2>>1>>0
		else{//청소할데가 있으면
			d = (d + 3) % 4;//회전=반시례로 90도는 시계로 270도니까
			if (d == 0) {//북
				if (arr[r - 1][c] == 0) {
					r = r - 1;
				}
			}
			else if (d == 1) {//동
				if (arr[r][c + 1] == 0) {
					c = c + 1;
				}
			}
			else if (d == 2) {//남
				if (arr[r + 1][c] == 0) {
					r = r + 1;
				}
			}
			else {//서
				if (arr[r][c - 1] == 0) {
					c = c - 1;
				}
			}
		}
	}

	cout << count;

	return 0;
}
반응형
반응형

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

 

1991번: 트리 순회

첫째 줄에는 이진 트리의 노드의 개수 N(1 ≤ N ≤ 26)이 주어진다. 둘째 줄부터 N개의 줄에 걸쳐 각 노드와 그의 왼쪽 자식 노드, 오른쪽 자식 노드가 주어진다. 노드의 이름은 A부터 차례대로 알파

www.acmicpc.net

 

 

 

💡 트리 순회

이진 트리를 입력받아 전위 순회(preorder traversal), 중위 순회(inorder traversal), 후위 순회(postorder traversal)한 결과를 출력하는 프로그램을 작성하시오.

예를 들어 위와 같은 이진 트리가 입력되면,
전위 순회한 결과 : ABDCEFG // (루트) (왼쪽 자식) (오른쪽 자식)
중위 순회한 결과 : DBAECFG // (왼쪽 자식) (루트) (오른쪽 자식)
후위 순회한 결과 : DBEGFCA // (왼쪽 자식) (오른쪽 자식) (루트)가 된다.

[입력]
첫째 줄에는 이진 트리의 노드의 개수 N(1 ≤ N ≤ 26)이 주어진다. 둘째 줄부터 N개의 줄에 걸쳐 각 노드와 그의 왼쪽 자식 노드, 오른쪽 자식 노드가 주어진다. 노드의 이름은 A부터 차례대로 알파벳 대문자로 매겨지며, 항상 A가 루트 노드가 된다. 자식 노드가 없는 경우에는 .으로 표현한다.

[출력]
첫째 줄에 전위 순회, 둘째 줄에 중위 순회, 셋째 줄에 후위 순회한 결과를 출력한다. 각 줄에 N개의 알파벳을 공백 없이 출력하면 된다.

 

 

 

✅ 문제 풀이
  • 트리를 전위, 중위, 후위 순회하는 방법은 각각의 함수를 재귀호출하는 방법이다.
  • 트리를 int타입의 2차원 배열에 넣을건데, 각 노드는 입력으로 받는 노드 즉 알파벳에서 'A'를 뺀 값을 인덱스로 받을 것이다. 따라서 A부터이므로, 0~25까지 인덱스를 사용하게 될 것이다. 그 인덱스의 첫번째 요소에는 left자식이, 두번째 요소에는 right자식이 들어가는 것이다.
  • 따라서 left에는 두번째로 입력받은 문자가 .이 아닐 경우 문자-'A' 한 값을 넣어주고, right도 세번째로 입력받은 문자에 대해 동일하게 처리한다.
  • 만약 문자가 .이라면 -1을 넣도록 한다.
  • preorder(n)함수를 선언한다. 이 함수는 노드 n부터 탐색할 것인데, 만약 n이 -1이라면 없는 노드인 것이므로 return하도록 하고, 그렇지 않다면 node n을 알파벳으로 출력하기 위해 n+'A'를 하여 알파벳으로 출력한다. 그런후 preorder(arr[n][0])와 preorder(arr[n][1])을 차례로 호출하여 재귀 호출되도록 한다.
  • inorder(n)함수를 선언한다. 이 함수는 노드 n부터 탐색할 것인데, 만약 n이 -1이라면 없는 노드인 것이므로 return하도록 하고, 그렇지 않다면 inorder(arr[n][0])를 호출한 후, n을 알파벳으로 출력하고, inorder(arr[n][1])을 호출한다.
  • postorder(n)함수를 선언한다. 이 함수는 노드 n부터 탐색할 것인데, 만약 n이 -1이라면 없는 노드인 것이므로 return하도록 하고, 그렇지 않다면 postorder(arr[n][0])와 postorder(arr[n][1])을 호출한 후, n을 알파벳으로 출력한다.
  • 각각의 함수들을 main함수에서 n=0으로 시작해 호출하고 결과를 확인한다.

 

 

✏ 코드 전문
#include<iostream>
#include<vector>
#include<string>
#include<math.h>

using namespace std;


void preorder(int n, vector<vector<int>> &arr) {
	if (n == -1) return;
	cout << (char)(n + 'A');
	preorder(arr[n][0], arr);
	preorder(arr[n][1], arr);
}
void inorder(int n, vector<vector<int>> &arr) {
	if (n == -1) return;
	inorder(arr[n][0], arr);
	cout << (char)(n + 'A');
	inorder(arr[n][1], arr);
}
void postorder(int n, vector<vector<int>> &arr) {
	if (n == -1) return;
	postorder(arr[n][0], arr);
	postorder(arr[n][1], arr);
	cout << (char)(n + 'A');
}

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

	int n;
	cin >> n;

	vector<vector<int>> arr(n);

	for (int i = 0; i < n; i++) {
		char node, l, r;
		cin >> node >> l >> r;
		int x = node - 'A';
		if (l == '.') {
			arr[x].push_back(-1);
		}
		else arr[x].push_back(l-'A');
		if (r == '.') {
			arr[x].push_back(-1);
		}
		else arr[x].push_back(r - 'A');
	}

	preorder(0, arr);
	cout << "\n";
	inorder(0, arr);
	cout << "\n";
	postorder(0, arr);
	cout << "\n";

	return 0;
}
반응형
반응형

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

 

2178번: 미로 탐색

첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

www.acmicpc.net

 

 

 

💡 미로 탐색

N×M크기의 배열로 표현되는 미로가 있다.

미로에서 1은 이동할 수 있는 칸을 나타내고, 0은 이동할 수 없는 칸을 나타낸다. 이러한 미로가 주어졌을 때, (1, 1)에서 출발하여 (N, M)의 위치로 이동할 때 지나야 하는 최소의 칸 수를 구하는 프로그램을 작성하시오. 한 칸에서 다른 칸으로 이동할 때, 서로 인접한 칸으로만 이동할 수 있다.위의 예에서는 15칸을 지나야 (N, M)의 위치로 이동할 수 있다. 칸을 셀 때에는 시작 위치와 도착 위치도 포함한다.

[입력]
첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

[출력]
첫째 줄에 지나야 하는 최소의 칸 수를 출력한다. 항상 도착위치로 이동할 수 있는 경우만 입력으로 주어진다.

 

 

 

✅ 문제 풀이
  • 처음에 시간초과가 발생했던 접근법
  1. miro라는 함수를 호출하여 (0,0)부터 출발하고, 동,서,남,북에 있는 값이 1이면 각각의 위치에서 miro함수를 재귀호출하는 방식을 통해 count해 나간다.
  2. 만약 miro함수에서 현재 위치가 (n-1,m-1)이면 현재까지의 count값과 answer값을 비교해서 작은 것을 answer로 갱신한다.

-> 이렇게 되면 n이 커질수록, 재귀호출 양이 많아져 시간 초과가 발생한다.

 

 

  • queue를 이용해 재귀호출을 하지않고 count하는 방식으로 문제를 해결!
  1. miro함수에 queue를 하나 생성한다. 
    이 queue는 pair로 <<행,렬>, count>로 데이터를 갖고 있다.
  2. queue에 {{0,0},1}을 추가해서 (0,0)위치에서 1카운트 된 것을 queue에 집어넣는다.
  3. 다음의 과정은 queue가 빌때까지 실행한다.
  4. queue의 front에서 행의 값을 r에, 열의 값을 c에, count를 count에 넣는다.
  5. 이제 여기는 방문한 것이므로 arr값을 0으로 바꾸어준다.
  6. 현재 위치가 (n-1,m-1)인지 확인해서 맞다면, 현재의 count값과 기존의 최소 count가 저장된 answer를 비교해서 더 작은 값으로 갱신해준다.
  7. 그리고 for문을 통해 현재 위치에서 상,하,좌,우에 있는 값이 1이면 queue에 해당 좌표와 현재의 count에서 +1한 값을 카운트로 넣어주고, 방문했음을 표시하기 위해 해당 위치의 arr값도 0으로 갱신해준다.
  8. miro함수가 끝나고 나면 answer에는 최소 이동 값만이 저장된다.

 

 

✏ 코드 전문
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include<queue>

using namespace std;

int n, m;

int answer = 10000;

int dx[] = { -1,1,0,0 };
int dy[] = { 0,0,-1,1 };

void miro(vector<vector<int>> &arr) {
	queue<pair<pair<int, int>, int>> q;
	q.push({ { 0, 0 }, 1 });
	arr[0][0] = 0;

	while (!q.empty()) {
		int r = q.front().first.first;
		int c = q.front().first.second;
		int count = q.front().second;

		q.pop();

		if (r == n - 1 && c == m - 1) {
			answer = min(answer, count);
			return;
		}

		for (int i = 0; i < 4; i++) {
			int x = r + dx[i];
			int y = c + dy[i];
			if (x >= 0 && x < n&&y >= 0 && y < m&&arr[x][y] == 1) {
				q.push({ {x,y}, count + 1 });
				arr[x][y] = 0;
			}
		}

	}

}
int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);

	cin >> n >> m;

	vector<vector<int>> arr(n);

	for (int i = 0; i < n; i++) {
		string str;
		cin >> str;
		for (int j = 0; j < str.length(); j++) {
			arr[i].push_back(str[j] - '0');
		}
	}

	miro(arr);

	cout << answer;
}
반응형
반응형

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

 

1004번: 어린 왕자

입력의 첫 줄에는 테스트 케이스의 개수 T가 주어진다. 그 다음 줄부터 각각의 테스트케이스에 대해 첫째 줄에 출발점 (x1, y1)과 도착점 (x2, y2)이 주어진다. 두 번째 줄에는 행성계의 개수 n이 주

www.acmicpc.net

 

 

 

💡 어린 왕자

어린 왕자는 소혹성 B-664에서 자신이 사랑하는 한 송이 장미를 위해 살아간다. 어느 날 장미가 위험에 빠지게 된 것을 알게 된 어린 왕자는, 장미를 구하기 위해 은하수를 따라 긴 여행을 하기 시작했다. 하지만 어린 왕자의 우주선은 그렇게 좋지 않아서 행성계 간의 이동을 최대한 피해서 여행해야 한다. 아래의 그림은 어린 왕자가 펼쳐본 은하수 지도의 일부이다.

빨간 실선은 어린 왕자가 출발점에서 도착점까지 도달하는데 있어서 필요한 행성계 진입/이탈 횟수를 최소화하는 경로이며, 원은 행성계의 경계를 의미한다. 이러한 경로는 여러 개 존재할 수 있지만 적어도 3번의 행성계 진입/이탈이 필요하다는 것을 알 수 있다.위와 같은 은하수 지도, 출발점, 도착점이 주어졌을 때 어린 왕자에게 필요한 최소의 행성계 진입/이탈 횟수를 구하는 프로그램을 작성해 보자. 행성계의 경계가 맞닿거나 서로 교차하는 경우는 없다. 또한, 출발점이나 도착점이 행성계 경계에 걸쳐진 경우 역시 입력으로 주어지지 않는다.

[입력]
입력의 첫 줄에는 테스트 케이스의 개수 T가 주어진다. 그 다음 줄부터 각각의 테스트케이스에 대해 첫째 줄에 출발점 (x1, y1)과 도착점 (x2, y2)이 주어진다. 두 번째 줄에는 행성계의 개수 n이 주어지며, 세 번째 줄부터 n줄에 걸쳐 행성계의 중점과 반지름 (cx, cy, r)이 주어진다.

[출력]
각 테스트 케이스에 대해 어린 왕자가 거쳐야 할 최소의 행성계 진입/이탈 횟수를 출력한다.

 

 

 

✅ 문제 풀이
  • 행성계를 이탈해야하는 경우와 진입해야 하는 경우로 나누어서 생각할 수 있다.
  1. 행성계를 이탈해야 하는 경우
    - 출발점이 행성계의 내부에 있고, 도착점이 행성계의 외부에 있는 경우
  2. 행성계에 진입해야 하는 경우
    - 도착점이 행성계의 내부에 있고, 출발점이 행성계의 외부에 있는 경우
  • 따라서 동일한 행성계 내에 출발점과 도착점이 존재한다면 이탈/진입하지 않는다.
  • 최종 이탈 + 진입 횟수를 구하면 정답이 된다.

 

✏ 코드 전문
#include<iostream>
#include<math.h>
using namespace std;

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

	int T;
	cin >> T;

	for (int i = 0; i < T; i++) {
		int x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;//출발점, 도착점

		int n;//행성계의 개수
		cin >> n;

		int en = 0;
		int dep = 0;

		for (int j = 0; j < n; j++) {
			int cx, cy, r;
			cin >> cx >> cy >> r;

			//출발점을 포함하는 행성계는 이탈, 도착점을 포함하는 행성계는 진입
			if (pow(cx - x1, 2) + pow(cy - y1, 2) <= r*r) {//출발점이 행성계안에있고
				if (pow(cx - x2, 2) + pow(cy - y2, 2) > r*r) {//도착점이 행성계 밖에 있는경우
					dep++;//이탈
				}
			}
			if (pow(cx - x2, 2) + pow(cy - y2, 2) <= r*r) {//도착점이 행성계안에있고
				if (pow(cx - x1, 2) + pow(cy - y1, 2) > r*r) {//출발점이 행성계 밖에 있는경우
					en++;//진입
				}
			}
		}
		cout << en + dep<<"\n";
	}
	return 0;
}
반응형
반응형

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

 

1541번: 잃어버린 괄호

첫째 줄에 식이 주어진다. 식은 ‘0’~‘9’, ‘+’, 그리고 ‘-’만으로 이루어져 있고, 가장 처음과 마지막 문자는 숫자이다. 그리고 연속해서 두 개 이상의 연산자가 나타나지 않고, 5자리보다

www.acmicpc.net

 

 

💡 잃어버린 괄호

세준이는 양수와 +, -, 그리고 괄호를 가지고 식을 만들었다. 그리고 나서 세준이는 괄호를 모두 지웠다.그리고 나서 세준이는 괄호를 적절히 쳐서 이 식의 값을 최소로 만들려고 한다.괄호를 적절히 쳐서 이 식의 값을 최소로 만드는 프로그램을 작성하시오.

[입력]
첫째 줄에 식이 주어진다. 식은 ‘0’~‘9’, ‘+’, 그리고 ‘-’만으로 이루어져 있고, 가장 처음과 마지막 문자는 숫자이다. 그리고 연속해서 두 개 이상의 연산자가 나타나지 않고, 5자리보다 많이 연속되는 숫자는 없다. 수는 0으로 시작할 수 있다. 입력으로 주어지는 식의 길이는 50보다 작거나 같다.

[출력]
첫째 줄에 정답을 출력한다.

 

 

 

✅ 문제 풀이
  • 주어지는 수식에서 부호는 + 또는 - 밖에 주어지지 않는다.
  • 따라서 -부호 뒤에 오는 수식은 다음 - 부호가 오기 전까지는 괄호로 묶어 전체를 -값으로 계산할 수 있다.
    이때의 값이 이 수식의 최소값이 될 것이다.
  • 그럼 주어지는 수식에서 첫번째로 주어지는 -부호 이후에 오는 숫자들은 모두 -가 붙어서 계산된다고 생각할 수 있다.
  • 따라서 첫번째 -부호가 부호들 중에서 몇번째로 등장하는지 카운트 해 줄것이다.
  • 그리고 부호가 아닌 문자열은 숫자로 판단하여, temp라는 저장소에 계속해서 업데이트 하며 값을 계산할 것이고, 부호가 등장했을 때는 숫자값을 넣어두는 벡터에 temp값을 넣고, temp는 다시 0으로 초기화 해줄것이다.
  • 이렇게 되면 마지막 숫자에 대해서는 부호로 끝나지 않기때문에, temp에 저장된 숫자 값이 벡터에 들어가지 않고 끝나기 때문에, 마지막에는 벡터에 temp값을 한번 더 추가해준다.
  • 위의 과정은 입력으로 받는 문자열을 하나씩 탐색해가면서 판단하는 것이다.
  • 문자열을 모두 순회한 뒤에는, 숫자가 담긴 벡터 arr와, 첫번째 -부호의 위치를 갖는 cnt가 결정되게 된다.
  • 따라서 arr의 크기만큼 순회하면서, 현재 arr의 인덱스가 cnt이하이면 각각을 sum에 더하고, cnt를 초과하면서부터는 sum에서 빼는 방식으로 계산해주면 된다.
  • 그럼 최종 최소값이 sum에 저장되고, 출력하면 된다.

 

#include<iostream>
#include<vector>
#include<string>

using namespace std;

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

	string str;
	cin >> str;

	int temp = 0;
	int res = 0;
	//한번 마이너스가 발생하고 나면 그 뒤로는 +에 대해서는 다 -로 묶을수 있으니까 마이너스 발생 후에는 모두 -로 계산

	vector<int> arr;
	int cnt = 0;
	int cntbreak = false;
	for (int i = 0; i < str.size(); i++) {
		if (str[i] != '+'&&str[i] != '-') {//숫자이면
			temp *= 10;
			temp += str[i] - '0';
		}
		else {
			arr.push_back(temp);
			temp = 0;

			if (!cntbreak&&str[i] == '+') cnt++;
			else if (str[i] == '-') cntbreak = true;
		}
	}

	arr.push_back(temp);

	for (int i = 0; i < arr.size(); i++) {
		if (i <= cnt) {
			res += arr[i];
		}
		else {
			res -= arr[i];
		}
	}

	cout << res;

	return 0;
}
반응형
반응형

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

 

1388번: 바닥 장식

형택이는 건축가이다. 지금 막 형택이는 형택이의 남자 친구 기훈이의 집을 막 완성시켰다. 형택이는 기훈이 방의 바닥 장식을 디자인했고, 이제 몇 개의 나무 판자가 필요한지 궁금해졌다. 나

www.acmicpc.net

 

 

💡 바닥 장식

형택이는 건축가이다. 지금 막 형택이는 형택이의 남자 친구 기훈이의 집을 막 완성시켰다. 형택이는 기훈이 방의 바닥 장식을 디자인했고, 이제 몇 개의 나무 판자가 필요한지 궁금해졌다. 나무 판자는 크기 1의 너비를 가졌고, 양수의 길이를 가지고 있다. 기훈이 방은 직사각형 모양이고, 방 안에는 벽과 평행한 모양의 정사각형으로 나누어져 있다.이제 ‘-’와 ‘|’로 이루어진 바닥 장식 모양이 주어진다. 만약 두 개의 ‘-’가 인접해 있고, 같은 행에 있다면, 두 개는 같은 나무 판자이고, 두 개의 ‘|’가 인접해 있고, 같은 열에 있다면, 두 개는 같은 나무 판자이다.기훈이의 방 바닥을 장식하는데 필요한 나무 판자의 개수를 출력하는 프로그램을 작성하시오.

[입력]
첫째 줄에 방 바닥의 세로 크기N과 가로 크기 M이 주어진다. 둘째 줄부터 N개의 줄에 M개의 문자가 주어진다. 이것은 바닥 장식 모양이고, '-‘와 ’|‘로만 이루어져 있다. N과 M은 50 이하인 자연수이다.

[출력]
첫째 줄에 문제의 정답을 출력한다.

 

 

✅ 문제 풀이
  • 문제에서 주어진 조건을 고려하기만 하면 쉽게 풀리는 문제이다.
  • 같은 행에서 -가 반복된다면 같은 판자인것이고, 같은 열에서 |가 반복된다면 같은 판자인 것이다.
  • 먼저 크기가 N*M인 배열에 -와 |를 입력 받고, N*M만큼 순회한다.
  • i는 행의 번호, j는 열의 번호인데, 행을 순회할 때마다 첫번째 값을 일단 row라는 변수에 저장해 두고, 이 값을 비교하면서 몇개의 나무 판자가 필요한지 카운트 할 것이다. 이때 각 행의 첫번째 요소는 비교 기준이 되므로 일단 count를 하나 올리고 시작한다.
  • 일단 현재의 row가 -인지 |인지 상관없이, 동일한 행안의 요소들을 비교하면서 현재 row와 현재 순회한 값 arr[i][j]가 다르다면 count해준다.
  • 그런다음, 두번째 줄 행부터 앞에 행의 동일한 열에 있는 값과 현재 값을 비교해서, 동일하면서 |이면 count를 하나 빼준다.
  • 그러면 -로는 연속한 것끼리 하나의 판자로, |로 연속한 것끼리 하나의 판자로 계산되어 최종 필요한 판자의 개수를 구할 수 있게 된다. 

 

✏ 코드 전문
#include<iostream>
#include<string>
#include<vector>

using namespace std;

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

	int N, M;
	cin >> N >> M;

	vector<vector<char>> arr(N);

	for (int i = 0; i < N; i++) {
		string str;
		cin >> str;

		for (int j = 0; j < str.length(); j++) {
			arr[i].push_back(str[j]);
		}
	}

	int count = 0;

	for (int i = 0; i < N; i++) {
		char row = arr[i][0];
		count++;

		if (i > 0 && row == '|'&&row == arr[i - 1][0]) count--;

		for (int j = 1; j < M; j++) {
			if (row != arr[i][j]||(row==arr[i][j] && row=='|')) {
				count++;
				row = arr[i][j];
			}
			if (i > 0 && arr[i][j] == '|'&&arr[i][j] == arr[i - 1][j]) count--;
		}
	}

	cout << count;

	return 0;
}
반응형

+ Recent posts