추억의 경찰대 문제 해답편입니다.
대부분 이 문제가 몬티홀 문제와 동치라고 생각하시는 것 같습니다.
사실 이 문제는 몬티홀 문제와 같지 않습니다.
정확한 해답을 알기 위해 저 대신 수사 상황을 반복시행할 프로그램을 작성했습니다.
int tryNum = 0; //전체 시행 횟수.
int effectiveNum = 0; //유효한 시행의 횟수.
int criminalIsFisrt = 0; //수사반장이 수사하고 있는 놈이 범인인 횟수
//용의자들의 타입을 지정합니다.
public enum suspectsType{
criminal, //범인!!!!!!.
suspect, //범인이 아닙니다. 하지만 과학수사팀에서 결백을 밝히지 못합니다.
innocent //범인이 아닙니다. 과학수사팀에서 결백을 밝힐수 있습니다.
}
suspectsType[] suspects = new suspectsType[3]; //용의선상에 올라온 것은 3명.
void tryInvestigationManyTime(){
//수사 상황 1.
tryNum = effectiveNum = criminalIsFisrt = 0;
for(int i=0; i < 1000000 ; i++)
tryInvestigation1();
Debug.Log ("Type1 ) try num = " + tryNum +
" /effectiveNum = " + effectiveNum +
" /criminalIsFirst = " + criminalIsFisrt +
" /ratio = " + ((float)criminalIsFisrt / effectiveNum));
//수사 상황 2.
tryNum = effectiveNum = criminalIsFisrt = 0;
for(int i=0; i < 1000000 ; i++)
tryInvestigation2();
Debug.Log ("Type2 ) try num = " + tryNum +
" /effectiveNum = " + effectiveNum +
" /criminalIsFirst = " + criminalIsFisrt +
" /ratio = " + ((float)criminalIsFisrt / effectiveNum));
//수사 상황 3.
tryNum = effectiveNum = criminalIsFisrt = 0;
for(int i=0; i < 1000000 ; i++)
tryInvestigation3();
Debug.Log ("Type3 ) try num = " + tryNum +
" /effectiveNum = " + effectiveNum +
" /criminalIsFirst = " + criminalIsFisrt +
" /ratio = " + ((float)criminalIsFisrt / effectiveNum));
}
//랜덤으로 용의자와 범인을 섞습니다.
void allocSuspects(){
//랜덤으로 suspect 와 innocent 를 섞어 넣습니다.
for(int i =0; i < 3; i++){
if(Random.Range(0.0f, 100.0f) < 50.0f) //결백함을 밝힐 수 있는 확률을 50%라고 하겠습니다.
suspects[i] = suspectsType.innocent;
else
suspects[i] = suspectsType.suspect;
}
suspects[Random.Range(0,3)] = suspectsType.criminal; //범인을 무작위의 위치에 넣습니다.
}
//수사상황 1) 은 과학수사팀이 용의자 두사람을 동시에 조사하여
// 적어도 한명이 결백한 사람으로 밝혀지면 수사반장에게 알리는 상황입니다.
void tryInvestigation1(){
tryNum++;
allocSuspects(); //랜덤으로 용의자를 배치합니다.
//수사반장은 0번 을 지목했습니다.
//과학수사팀은 1,2번의 결백을 가려냅니다.
//적어도 둘 중 1명의 결백을 밝힐 수 있어야 유효한 시행으로 처리합니다.
if(suspects[1] != suspectsType.innocent && suspects[2] != suspectsType.innocent){
return; //이 경우 결백한 사람이 누군지 밝힐 수 없으므로 여기서 끝.
}
effectiveNum++; //이제부터는 유효한 시행입니다.
//과학수사팀은 둘중의 한명이 결백함을 수사반장에게 알렸을 것입니다.
//이때 수사반장이 수사하고 있던 용의자가 범인인지 확인합니다.
if(suspects[0] == suspectsType.criminal)
criminalIsFisrt++;
}
//수사상황2)는 과학수사팀이 용의자를 순차적으로 조사하는데,
//우연히 첫번째 사람이 결백함이 밝혀져 수사반장에게 알리는 상황입니다.
void tryInvestigation2(){
tryNum++;
allocSuspects(); //랜덤으로 용의자를 배치합니다.
//수사반장은 0번 을 지목했습니다.
//과학수사팀은 1,2번의 결백을 가려냅니다.
//과학수사팀이 1번째 용의자를 수사해서 그가 결백하다는게 밝여져야 유효한 상황입니다.
if(suspects[1] != suspectsType.innocent){
return; //위의 상황에 해당하지 않으면, 여기서 끝.
}
effectiveNum++; //이제부터는 유효한 시행입니다.
//과학수사팀은 1번째 용의자의 결백함을 수사반장에게 알렸을 것입니다.
//이때 수사반장이 수사하고 있던 용의자가 범인인지 확인합니다.
if(suspects[0] == suspectsType.criminal)
criminalIsFisrt++;
}
//수사상황 3)은 과학수사팀이 용의자 두 사람을 동시에 조사합니다.
//그런데 두사람의 조사결과가 동시에 나왔습니다.
//이때 정확히 둘 중 한 명만 결백함을 밝혀졌을 때, 수사반장에게 알려줍니다.
void tryInvestigation3(){
tryNum++;
allocSuspects(); //랜덤으로 용의자를 배치합니다.
//수사반장은 0번 을 지목했습니다.
//과학수사팀은 1,2번의 결백을 가려냅니다.
//딱 1명만 결백함이 밝혀져야 유효한 경우입니다.
if((suspects[1] == suspectsType.innocent && suspects[2] == suspectsType.innocent) ||
(suspects[1] != suspectsType.innocent && suspects[2] != suspectsType.innocent)){
return; //위의 상황에 해당하지 않으면, 여기서 끝.
}
effectiveNum++; //이제부터는 유효한 시행입니다.
//과학수사팀은 결백한 사람이 누군지 수사반장에게 알렸을 것입니다.
//이때 수사반장이 수사하고 있던 용의자가 범인인지 확인합니다.
if(suspects[0] == suspectsType.criminal)
criminalIsFisrt++;
}
여기까지가 작성된 코드입니다.
tryInvestigationManyTime() 메쏘드를 실행시키면 결과 값을 알 수 있습니다.
****
다시 정리할게요. 이 시뮬레이션은 세 개의 상황을 가정하고 각각의 상황에서 확률이 어떻게 다른가를 봅니다.
수사 상황 1)과학수사팀은 두명의 용의자를 동시에 조사하는데, 조사결과는 동시에 나오지 않습니다. 이때 적어도 둘 중 한 명이 결백함을 알아내면 곧바로 수사반장에 알립니다.
수사 상황 2)과학수사팀은 순차적으로 용의자를 수사하는데 우연히 처음 조사한 사람이 결백함을 알아내어 수사반장에게 알립니다.
수사상황 3)과학수사팀이 두명의 용의자를 동시에 수사하는데, 조사결과가 동시에 나오는 경우입니다. 이땐 정확히 둘 중 한 명만 결백해야 수사반장에게 알립니다. 둘다 결백하다면 수사반장이 조사하던 놈이 범인일테니까 '그 놈이 범인'이라고만 해주면 됩니다.
****************
그럼 결과를 공개합니다. 끝부분의 ratio 값이 중요합니다.
이 값은 수사반장이 조사하던 사람이 범인일 확률입니다.
Type1 ) try num = 1000000 /effectiveNum = 583151 /criminalIsFirst = 250147 /ratio = 0.4289575
Type2 ) try num = 1000000 /effectiveNum = 333086 /criminalIsFirst = 166398 /ratio = 0.4995647
Type3 ) try num = 1000000 /effectiveNum = 500094 /criminalIsFirst = 166932 /ratio = 0.3338012
수사상황1)일 경우 0.33 도 아니고 0.5도 아닌 값이죠?
이건 몬티홀 문제도 우연히 넘어진 몬티홀 문제도 아님을 알 수 있습니다.
그에 반해 수사상황2)는 우연히 넘어진 몬티홀,
수사상황3)은 몬티홀의 확률을 따르고 있는 것처럼 보입니다.
**************
그런데 여기서 주의할 점이 있습니다.
사실 이 결과들은 과학 수사팀이 결백을 밝혀낼 수 있는 확률과 연결되어있습니다.
위에서는 과학 수사팀이 결백함을 밝힐 수 있는 확률을 50% 로 했습니다.
즉, 정말 결백한 사람이라고 하더라도 과학 수사팀이 결백하다고 밝힐 수 있는 사람은 절반뿐이란 이야깁니다.
******
그럼 결백함을 밝힐 수 있는 확률을 90%로 놓아보겠습니다.
Type1 ) try num = 1000000 /effectiveNum = 930238 /criminalIsFirst = 330155 /ratio = 0.3549145
Type2 ) try num = 1000000 /effectiveNum = 599505 /criminalIsFirst = 299527 /ratio = 0.4996239
Type3 ) try num = 1000000 /effectiveNum = 659757 /criminalIsFirst = 60107 /ratio = 0.09110475
수사상황1)일 경우의 값이 점점 몬티홀의 경우와 같아짐을 알 수 있습니다.
수사상황2)의 경우는 과학수사반의 능력과는 관계없이 그냥 5:5입니다.
수사상황3)이 경우는 과학수사팀이 결백함을 밝히지 못한 사람이 범인일 확률이 높아진 결과겠죠?
***********
이제 반대로 과학수사팀이 무능력해서 결백함을 밝힐 수 있는 확률이 10%라고 해보겠습니다.
Type1 ) try num = 1000000 /effectiveNum = 129518 /criminalIsFirst = 63193 /ratio = 0.487909
Type2 ) try num = 1000000 /effectiveNum = 66270 /criminalIsFirst = 33285 /ratio = 0.5022635
Type3 ) try num = 1000000 /effectiveNum = 126575 /criminalIsFirst = 59879 /ratio = 0.4730713
수사상황1)과 3)은 동시에 확률이 올라갑니다. 어쨌든 0.5에는 미치지 못합니다.
수사상황2)는 5:5를 계속 유지합니다.
***********
결론입니다.
문제와 같은 상황이 발생할 경우, 먼저 과학 수사팀에 걸어 수사상황2)와 같은 상황인지 물어봅니다.
만약 그렇다면 바꾸나 안바꾸나 확률은 5:5입니다.