문제 링크 : https://www.acmicpc.net/problem/16891
"물리학" 카테고리에 있는 문제들을 풀어보다가 이 문제가 재미있게 생겨서 풀어보았다. 예전에 이런 충돌수에 관련된 문제를 3Blue1Brown 이라는 굉장히 좋은(?) 채널에서 본 적이 있다.
유튜브 영상
이 영상에서는 두번째 물체의 질량이 100의 거듭제곱 꼴일 때 충돌횟수가 π의 앞의 자리수가 되는 이유를 설명해주고 있는데 예전에 흥미롭게 봤던 경험이 있어서 생각이 났다.
1. 문제 풀이
먼저 알아야할 것은 두 번째 물체의 초기속력이 0만 아니라면 충돌수에 영향을 주지 않는다는 것이다. 만약 첫 번째 물체의 초기속력이 있었다면 상관이 있겠지만 첫 번째 물체의 초기속력이 0이므로 두 번째 물체가 어떤 속력을 가지든 속력비율은 항상 일정하기 때문이다. 근데 소수점계산에서 오류가 발생할 수도 있기 때문에 두 번째 물체의 초기속력은 큰 수로 해주자.
double v1=0,v2=-100000000;
*참고로 여기서 - 부호는 왼쪽 방향을 의미한다.
이제 충돌을 고려해주자. 충돌은 물체와 물체, 벽과 물체 사이에서 일어난다. 물체와 물체 사이의 충돌이 먼저 일어나므로 이를 먼저 생각해보자.
while(true)
{
double u1 = ((m1-m2)/(m1+m2))*v1 + (2*m2/(m1+m2))*v2;
double u2 = (2*m1/(m1+m2))*v1 - ((m1-m2)/(m1+m2))*v2;
collision ++; //충돌수
v1 = u1;
v2 = u2;
}
문제에 주어진 공식에 따라 충돌 후 속도 u1과 u2를 위와 같이 구할 수 있다.
벽과 물체 사이 충돌은 v1의 부호가 -일 때 일어나고, 벽과 충돌 후 속력의 변화는 없다.
if(v1 < 0)
{
collision ++;
v1 *= -1;
}
마지막으로 충돌이 끝날 조건은 첫 번째 물체에 대한 두 번째 물체의 상대속도가 오른쪽방향(양수)일 때이다.(단, 첫 번째 물체의 속도가 0 또는 오른쪽 방향일 때)
if(v2 - v1 >= 0)
{
break;
}
2. 시행 착오
처음에 속도의 부호(방향)를 고려하지 않고 코드를 짜서 살짝 당황했다.
3. 코드
#include <iostream>
using namespace std;
int main()
{
long long N,collision=0;
cin>>N;
double v1=0,v2=-100000000,m1=1,m2=N*N;
while(true)
{
double u1 = ((m1-m2)/(m1+m2))*v1 + (2*m2/(m1+m2))*v2;
double u2 = (2*m1/(m1+m2))*v1 - ((m1-m2)/(m1+m2))*v2;
collision ++;
v1 = u1;
v2 = u2;
if(v1 < 0)
{
collision ++;
v1 *= -1;
}
if(v2 - v1 >= 0)
{
break;
}
}
cout<<collision;
}
실제로 코드에서 N이 10의 거듭제곱(N^2이 100의 거듭제곱)일 때 π에서 등장하는 수들이 나오는 것을 확인할 수 있다.
'정보 > 백준 문제풀이' 카테고리의 다른 글
백준 28218번 격자 게임(2023 KOI 중등부 2번) C++(게임 이론) (0) | 2024.05.11 |
---|---|
백준 1005번 ACM Craft C++ (0) | 2024.04.21 |
백준 30928번 Yokohama Phenomena C++ (1) | 2024.03.23 |
백준 8983번 사냥꾼 C++ (0) | 2024.03.19 |
백준 10166번 관중석 C++ (0) | 2024.03.19 |