정보/백준 문제풀이

백준 16891번 탄성충돌 C++ (물리)

FeatherCoder 2024. 3. 24. 12:30

 

문제 링크 : https://www.acmicpc.net/problem/16891
 

16891번: 탄성 충돌

탄성 충돌은 운동 에너지가 보존되는 충돌이다. 일차원 상에서 질량이 m1, m2인 두 물체가 각각 속도(여기서 속도는 방향을 포함하는 양이다) u1, u2로 운동하다가 탄성 충돌하면 충돌 후 두 물체

www.acmicpc.net

 

 "물리학" 카테고리에 있는 문제들을 풀어보다가 이 문제가 재미있게 생겨서 풀어보았다. 예전에 이런 충돌수에 관련된 문제를 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의 거듭제곱)일 때 π에서 등장하는 수들이 나오는 것을 확인할 수 있다.