2 분 소요

톱니바퀴 (백준 Gold 5)

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

8 개의 ‘극’을 가진 4개의 톱니바퀴 정보가 주어지고
특정 톱니바퀴를 시계/반시계 로 회전시키는 t개의 정보가 주어질때
마지막 회전 이후, 톱니바퀴들의 위쪽에 있는 것이 S극이라면
pow(2, 각 톱니바퀴의 번호(0~3)) 를 더하여 반환하는 문제

  • 톱니바귀 정보
    0 : N극
    1 : S극
    (시계 방향으로 주어짐)

  • 회전 정보
    2개의 정수로
    첫 정수가 ‘회전시킬 톱니바퀴 번호’
    두번째가 ‘회전 방향’
    (1이면 시계, -1이면 반시계)

풀이 방법

벡터 내부를 실제로 회전시키는 방식은 비효율적이므로
그냥 Top을 가리키는 인덱스를 사용하기로 하였다
(Queue로 해볼까도 싶었지만,
Left,Right에 해당하는 수치에도 접근이 가능해야 해야 했기에)

  • 그렇기에 맨 위의 인덱스를 저장하는 vector 사용
  • 이후 원본 값 벡터를 별도로 저장

  • 이후, 인덱스를 0~7 사이에 두며 인덱스의 범위를 Clamp한다
    (0에서 -1이 되면, 7로, 7에서 8이 되면 0으로)
    (엄밀히 말하면 Clamp와는 조금 다르지만)

  • 추가로 유의할 점은
    톱니바퀴 자체의 회전은 맨 마지막에 하는 것이다
    (먼저 회전시키면, 옆의 톱니바퀴와 비교하기 힘들어짐)
    동시에, 방향을 둘로 나누어 재귀를 태우는 방식을 사용하였다

제출 코드

#include<iostream>
#include<string>
#include<vector>
#include<math.h>

using namespace std;

int getValue(vector<vector<int>>& vv, vector<int>& iv)
{
	int res = 0;

	for (int i = 0; i < 4; i++)
	{
		if (vv[i][iv[i]] == 1)
		{
			res += pow(2, i);
		}
	}

	return res;
}

int getRightIndex(int idx, int value)
{
	int ret = idx + value;
	if (ret >= 8)
		ret %= 8;
	else if (ret < 0)
		ret = 8 + ret;

	return ret;
}

int getLeftValue(vector<vector<int>>& vv, int gearNum, int startIdx)
{
	int tIdx = getRightIndex(startIdx, -2);
	return vv[gearNum][tIdx];
}

int getRightValue(vector<vector<int>>& vv, int gearNum, int startIdx)
{
	int tIdx = getRightIndex(startIdx, 2);
	return vv[gearNum][tIdx];
}

void Spin(vector<vector<int>>& vv, vector<int>& iv, int nowGear, int dir, bool bRight)
{
	if (nowGear >= 4 || nowGear < 0)
		return;

	if (bRight)
	{
		if (nowGear < 3 &&
			getRightValue(vv, nowGear, iv[nowGear]) != getLeftValue(vv, nowGear + 1, iv[nowGear + 1]))
		{
			Spin(vv, iv, nowGear + 1, -dir, bRight);
		}
	}
	else
	{
		if (nowGear > 0 &&
			getLeftValue(vv, nowGear, iv[nowGear]) != getRightValue(vv, nowGear - 1, iv[nowGear - 1]))
		{
			Spin(vv, iv, nowGear - 1, -dir, bRight);
		}
	}

	iv[nowGear] = getRightIndex(iv[nowGear], dir);
}

void StartSpin(vector<vector<int>>& vv, vector<int>& iv, int nowGear, int dir)
{
	if (nowGear < 3 &&
		getRightValue(vv, nowGear, iv[nowGear]) != getLeftValue(vv, nowGear + 1, iv[nowGear + 1]))
		Spin(vv, iv, nowGear + 1, -dir, true);

	if (nowGear > 0 &&
		getLeftValue(vv, nowGear, iv[nowGear]) != getRightValue(vv, nowGear - 1, iv[nowGear - 1]))
		Spin(vv, iv, nowGear - 1, -dir, false);

	iv[nowGear] = getRightIndex(iv[nowGear], dir);
}

int main()
{
	// 시작 위치를 가리키는 녀석을 기준으로 순회하는 것을 추천함
	// 그리고 시작 위치만 이동시키면 비교할 수 있음
	vector<vector<int>> valueVec;
	for (int i = 0; i < 4; i++)
	{
		valueVec.push_back(vector<int>());
		string t;
		cin >> t;
		for (int j = 0; j < 8; j++)
		{
			valueVec[i].push_back(t[j] - '0');
		}
	}

	int t;
	cin >> t;
	vector<int> topIdx(4, 0);
	while (t > 0)
	{
		int gearNum, dir;
		cin >> gearNum >> dir;
		gearNum--;
		StartSpin(valueVec, topIdx, gearNum, -dir);

		t--;
	}

	cout << getValue(valueVec, topIdx);

	return 0;
}

결과

Image

문제를 2번정도 잘못보았다

  • 무조건 0번 톱니바퀴에서 시작하며
    회전량 + 방향 이 제공되는 줄 알았다

  • 정보가 ‘반시계’로 주어진줄 알았기에
    시계/반시계 에 대한 코드적인 혼란이 있었다

해당하는 부분들을 수정하니 통과할 수 있었다

댓글남기기