Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

16-bomik0221 #67

Merged
merged 2 commits into from
Mar 1, 2024
Merged

16-bomik0221 #67

merged 2 commits into from
Mar 1, 2024

Conversation

bomik0221
Copy link
Member

@bomik0221 bomik0221 commented Feb 24, 2024

🔗 문제 링크

9655번: 돌 게임
유형 : DP (new!)

✔️ 소요된 시간

40분

✨ 수도 코드

❔ 문제 이해

image

🤔 사고 과정

돌을 1개, 3개를 가져갈 수 있고 돌이 모두 소진되어야 끝난다 → DP..! (사실 DP 풀어보고 싶어서 DP 문제를 검색해서 풀었기에 유형은 알고 있었습니다.) DP인 건 알았는데, 어떻게 해야 할 지 감이 안 잡혀 조금 갈팡질팡 한 것 같네요.
그래서 정리해본 문제의 조건은 다음과 같습니다.

1. 상근이와 창영이가 번갈아 가며 돌을 가져가기
2. 돌은 한 턴에 1개 또는 3개를 가져갈 수 있음.

그리고 이 조건을 활용하여 다음과 같은 코드를 구상하였습니다.

우선 돌 개수 N을 입력받고 N+1 개의 인덱스를 가지는 배열을 만듭니다. 인덱스 개수가 N+1인 이유는, 가독성을 높이기 위해서.. !
image

첫 시작은 무조건 상근이가 한다는 조건이 있었으니, 상근이가 1개를 가져가는 경우와 3개를 가져가는 경우를 모두 기록합니다.
image

그리고 그 다음부터는, 돌이 모두 소진 될 때 까지, 즉 배열이 끝나는 시점까지 앞의 턴이 누구였는지를 검사해서 다음 턴에 오는 사람이 1개 또는 3개를 가져가는 경우를 모두 기록합니다. 상근이가 시작했으니 다음 차례는 창영이겠죠. 창영이가 1개와 3개를 가져가는 경우를 기록합니다.
image

이번엔 다시 상근이 차례겠죠. 상근이 차례인 것은 창영이가 앞 칸에 있다는 것으로 알 수 있습니다. 3번에는 이미 상근이가 기록되어 있지만, 신경쓰지 않고 3번과 5번에 다시 상근이를 기록해줍니다. 경우의 수가 여러 가지인 만큼, 도착한 칸에 누가 이미 있는지보다는 확실하게 전 칸에 누가 있었는지를 검사합니다. 그리고 해당 칸에 무엇이 있든 결과를 덮어씁니다. 그런데 어차피 이 게임은 1개 혹은 3개를 가져간다는 경우 뿐이어서, 해당 칸에 있던 사람이 바뀌는 경우는 없는 것 같습니다.
image

이와 같은 방식으로 배열을 전부 채우고 나면, game[5] 에 적혀있는 사람이 최종 우승자가 되겠죠. 이를 출력해주면 됩니다. 여기에서는 상근이가 되겠네요!

💭 첫 번째 코드

위의 사고 과정을 바탕으로 짠 첫 번째 코드입니다.
std::vector<std::string>을 사용하여, 배열에 처음부터 답에 출력되어야 할 문구인 SK 와 CY를 넣었습니다.

#include <iostream>
#include <vector>

int main() {
	int N; std::cin >> N;
	std::vector<std::string> game(N+1, "");
	game[1] = "SK";	game[3] = "SK";	//초기화

	for (int i = 2; i <= N; i++) {
		if (game[i - 1] == "SK") {
			game[i] = "CY";
			if(i+2 <=N)	game[i + 2] = "CY";	//i+2 값이 배열을 벗어나면 입력 패스
		}
		else {
			game[i] = "SK";
			if (i + 2 <= N)	game[i + 2] = "SK";
		}
	}

	std::cout << game[N];

	return 0;
}

하지만 이 코드에는 슬픈 비밀이...
image
코드도 짧은데, 대체 왜 메모리 초과가??? 그런데.. 허무할정도로 쉬운 해결법...

💬 최종 코드

vector속 값을 int로 바꿔주니까 바로 성공!! 숫자로 된 벡터가 메모리가 훨씬 적어서 코드 구조가 완전 동일한데도 이 코드는 정답 처리가 되었습니다. 대신 가독성이 좀 모자라긴 한데, 문제를 맞히려면 어쩔 수 없겠죠😅

#include <iostream>
#include <vector>

int main() {
	int N; std::cin >> N;
	std::vector<int> game(N+1, 0);
	game[1] = 1;	game[3] = 1;//초기화. 상근이가 1, 창영이가 2

	for (int i = 2; i <= N; i++) {
		if (game[i - 1] == 1) {
			game[i] = 2;
			if(i+2 <=N)	game[i + 2] = 2;
		}
		else {
			game[i] = 1;
			if (i + 2 <= N)	game[i + 2] = 1;
		}
	}

	if (game[N] == 1)	std::cout << "SK";
	else std::cout << "CY";

	return 0;
}

히히
image

📚 새롭게 알게된 내용 + 소감

메모리 관리에 대해 한 번 더 생각해보게 하는 문제였네요. 허허
new 유형 도전! DP는 다른 분들 PR로만 계속 보고 도저히 감이 안 잡혔었는데, 서당개 어쩌고... 원리로 드디어 깨우쳤습니다.
처음 볼 땐 정말 이게 뭐야? 싶었던 분얀데... 감을 잡으니 재밌는 것 같기도..?

Copy link
Member

@miniron-v miniron-v left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

상세한 설명 잘 봤습니다! DP 문제가 처음 하면 쉽지 않은데, 조건을 잘 거신 것 같네요.

#include <iostream>

int main() {
    int n;
    std::cin >> n;
    
    std::cout << ((n % 2 == 0) ? "CY" : "SK");
}

image

보미님 코드보고 넣어봤는데 성공하네요.... ㅇㅁㅇ


1개 또는 3개를 가져가므로 상근이는 항상 홀수 번째 돌만 가져가고, 창영이는 항상 짝수 번째 돌만 가져가게 되는 원리 같네요. 1~3개였다면 더 재밌었을지도...?

Comment on lines +6 to +7
std::vector<int> game(N+1, 0);
game[1] = 1; game[3] = 1; //상근이는 1, 창영이는 2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

더미 쓰신 김에 std::vector<int> game(N+1, 2);로 초기화하면 game[1] = 1; game[3] = 1; 구문을 삭제해도 됩니다.
이 경우 for문은 i = 1부터 시작하면 됩니다.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오~ 그런 방법이 있군요~!! 그럼 제가 짠 코드에서는 N+1, 1 로 초기화하면 for문을 i=2 부터 시작해도 같은 구조를 가질 수 있겠네요.. 생각 못 해본 포인트인데 짱입니다

Comment on lines +10 to +17
if (game[i - 1] == 1) {
game[i] = 2;
if(i+2 <=N) game[i + 2] = 2;
}
else {
game[i] = 1;
if (i + 2 <= N) game[i + 2] = 1;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i의 컨디션이 1, 2 두 가지 뿐이기에, bool을 쓰셔도 동일하게 동작합니다.

이땐 변수명을 "SKwin"처럼 지으면 알아보기 편하겠죠?

@bomik0221
Copy link
Member Author

상세한 설명 잘 봤습니다! DP 문제가 처음 하면 쉽지 않은데, 조건을 잘 거신 것 같네요.

#include <iostream>

int main() {
    int n;
    std::cin >> n;
    
    std::cout << ((n % 2 == 0) ? "CY" : "SK");
}

image

보미님 코드보고 넣어봤는데 성공하네요.... ㅇㅁㅇ

1개 또는 3개를 가져가므로 상근이는 항상 홀수 번째 돌만 가져가고, 창영이는 항상 짝수 번째 돌만 가져가게 되는 원리 같네요. 1~3개였다면 더 재밌었을지도...?

(대강 고수의 코드를 보고 기절했다는 글)

상세한 설명 잘 봤습니다! DP 문제가 처음 하면 쉽지 않은데, 조건을 잘 거신 것 같네요.

#include <iostream>

int main() {
    int n;
    std::cin >> n;
    
    std::cout << ((n % 2 == 0) ? "CY" : "SK");
}

image

보미님 코드보고 넣어봤는데 성공하네요.... ㅇㅁㅇ

1개 또는 3개를 가져가므로 상근이는 항상 홀수 번째 돌만 가져가고, 창영이는 항상 짝수 번째 돌만 가져가게 되는 원리 같네요. 1~3개였다면 더 재밌었을지도...?

허무해.. 저렇게 짧아질수있다니..

@2secondag
Copy link
Collaborator

상세한 설명 잘 봤습니다! DP 문제가 처음 하면 쉽지 않은데, 조건을 잘 거신 것 같네요.

#include <iostream>

int main() {
    int n;
    std::cin >> n;
    
    std::cout << ((n % 2 == 0) ? "CY" : "SK");
}

image

보미님 코드보고 넣어봤는데 성공하네요.... ㅇㅁㅇ

1개 또는 3개를 가져가므로 상근이는 항상 홀수 번째 돌만 가져가고, 창영이는 항상 짝수 번째 돌만 가져가게 되는 원리 같네요. 1~3개였다면 더 재밌었을지도...?

우와,,,,,,, 대박이네요.

Copy link
Collaborator

@2secondag 2secondag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드 잘 봤습니다~!
저도 문제 풀 때 메모리 초과가 생기면 어디서 메모리 초과가 생겼는지 몰라 굉장히 당황했던 기억이.....

수고하셨습니다~

@Redish03 Redish03 removed their request for review February 29, 2024 14:29
@bomik0221 bomik0221 merged commit 0ceee9a into main Mar 1, 2024
@bomik0221 bomik0221 deleted the 16-bomik0221 branch March 1, 2024 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants