2014. 5. 30. 17:13ㆍ알고리즘 문제풀기/각종 OJ 풀이
하루가 지나면 한 마을에서 다른 마을로 옮겨간다.
이때 내가 있던 마을에서 갈 마을이 여러 곳이면 그곳으로 각각 갈 확률이 n등분된다.
이때 d일이 지났을 때 각 장소에 박사가 있을 확률을 구하여라... 하는 문제이다.
일단은 확률이니까 경우의 수를 전체 경우의 수로 나눈다든가 하는 생각이 들 수도 있지만,
잘 생각을 해보면 d일째의 각 확률을 알고 있으면,
모든 모서리마다(모든 시작점과 끝점에 대해서)
(d+1)일째에 끝점에 있을 확률 +=
d일째에 시작점에 있을 확률 x (1 / (시작점에서 갈 수 있는 모서리의 수))
이 됨을 쉽게 알 수 있다.
모든 모서리에 대해서 이 작업을 d번 하면 되므로 시간복잡도는 O(dE)인데,
문제에서 이미 인접행렬을 주기 때문에, O(dV²)으로 풀 수 있겠다.
이 글에서 하고 싶은 말은,
이 문제는 어느 날짜의 확률을 가지고 그 다음 날짜의 확률을 구하는 문제로,
전형적인 다이나믹 문제라고 볼 수 있다.
인접행렬을 adj[][]라고 하면
for(i=0;i<n;i++){
for(j=0;j<n;j++){
if(adj[i][j]){
dyn[to][j] += dyn[from][i] / degree[i];
}
}
}
뭐 이런 식으로 표현할 수 있겠다.
그런데 우리는 바로 전날의 확률만 알면 되므로, 이틀 전, 3일 전의 행방(?)은 전혀 몰라도 된다.
그렇다면 배열을 딱 2개만 쓰면 되지 않을까?
바로 이것이다.
dyn[0]과 dyn[1]을 이용해서,
dyn[0]에 0일째(교도소가 있는 마을에 박사가 있을 확률이 1, 나머지는 다 0)를 대입한 후,
dyn[0]을 이용해서 dyn[1]을 구하고(1일째의 확률은 dyn[1]에)
dyn[1]을 이용해서 dyn[0]을 구하고(2일째의 확률은 dyn[0]에)
dyn[0]을 이용해서 dyn[1]을 구하고(3일째의 확률은 dyn[1]에)
...
이렇게 구현하면 되겠다.
라고 생각하고 그대로 풀면 확률이 이상하게 커질 것이다.
바로 위의 코드에서 확률에 += 연산을 이용해서 그냥 더하는데,
예를 들어 3일째의 확률을 구하기 위해서 dyn[1]에다가 값을 더할때,
dyn[1]에는 1일째의 확률이 그대로 들어있으므로 이를 매번 초기화해주는 작업이 필요할 것이다.
n제한 50, d제한 100이기 때문에 dn²=250000 이라서 문제가 너무 쉽게 풀리는 것 같다.
n제한 10만,모서리 갯수 제한 10만, d제한 250 정도로 하면,
위에서 인접행렬 대신 모든 모서리를 이용하는 방식으로 바꿀 수 있겠지.
(여기서 모서리를 복잡하게 저장하지 말고 그냥 시작점 끝점만 기록해놓는 게 훨씬 간단하겠지?)
그러면 O(dE) 풀이가 나오고 시간 안에 풀릴 듯 하다.
- 1) 두니발은 '한니발'의 패러디인 것 같다. 하나, 둘, ... [본문으로]
'알고리즘 문제풀기 > 각종 OJ 풀이' 카테고리의 다른 글
AtCoder (0) | 2016.09.04 |
---|---|
나코더 방학 연습 2주차 풀이 (0) | 2016.08.07 |
나코더 방학 연습 1주차 풀이 (0) | 2016.07.28 |
1591: 수열 복원 (0) | 2016.03.08 |
[KOISTUDY] [017D] [381] 격자 읽기 (0) | 2014.02.25 |