swexpert

[swexpert] 1266. 소수 완제품 확률 (C++, 조합)

해랑쓰 2021. 9. 29. 15:16
728x90
반응형

일단 1~18 사이 소수를 먼저 구해준 후 A가 소수 개를 성공할 확률, B가 소수 개를 성공할 확률을 구한다.

 

만약 A가 2개를 성공한다고 칠 때 18개의 구간 중 어느 구간 2개에서 성공하는 지를 구해줘야 하므로

18C2를 구해서 a의 2개 성공확률에 곱해줘야 된다.

 

둘 중 적어도 하나가 소수인 확률은 전체확률인 1에서 둘다 소수가 아닌 확률(여집합)을 빼주면 된다.

 

교집합을 구하는 방법과 소수개를 성공할 확률을 구하는 것까지는 잘 했는데 조합을 구해줘야 된다는 것을

떠올리지 못해 못 풀어서 해당 부분은 참고해서 했다.

조합은 nCr=n-1Cr-1 +n-1Cr의 식을 참고하여 이중배열로 미리 구해준다.

 

#define _CRT_SECURE_NO_DEPRECATE
#include <iostream>
#include <string>
#include <vector>
using namespace std;

int t;
double a, b;
bool prime[39];
double res;
int comb[19][19];


void getComb() {// 18중 n개를 뽑을 조합을 구해줘야된다
	for (int i = 1; i <= 18; i++) {
		comb[i][0] = 1;
		comb[i][i] = 1;
	}

	for (int i = 2; i <= 18; i++) {
		for (int j = 1; j < i; j++) {
			comb[i][j] = comb[i - 1][j - 1] + comb[i - 1][j];
		}
	}


}

void PrimeCheck() {
	fill(prime, prime+19, true);
	prime[0] = false;
	prime[1] = false;
	//2부터 18까지 수들 중 소수 판별
	for (int i = 2; i <= 18; i++) {
		for (int j = 2; j*j <= i; j++) {
			if (i%j == 0) {
				prime[i] = false;
				break;
			}
		}
	}
}

double getPercent(double percent, int num) {
	double ans = 1;
	for (int i = 0; i < num; i++) {
		ans *= percent/100; //완제품 성공률
	}
	for (int i = 0; i < 18 - num; i++) {
		ans *= (100 - percent)/100;
	}

	return ans;
}

void getResult() {
	double suma = 0, sumb = 0;
	double ans = 0, ans2 = 0;
	for (int i = 0; i <= 18; i++) {
		if (!prime[i]) {// 소수라면
			suma = getPercent(a, i);//i개 성공확률
			ans = ans + comb[18][i] * suma;
			sumb = getPercent(b, i);
			ans2 = ans2 + comb[18][i] * sumb;

		}
	}
	
	//전체 확률에서 두개 모두 소수가 아닐 확률을 빼주면 된다.
	// 그럼 적어도 둘 중 하나는 소수겠지. (합집합부분)
	res = 1 -  ans*ans2;
}




int main(void) {

	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout << fixed;
	cout.precision(6);

	PrimeCheck();
	getComb();
	cin >> t;
	for (int tc = 1; tc <= t; tc++)
	{
		cin >> a >> b;
		res = 0;
		getResult();

	
		cout << "#" << tc <<" "<< res<<"\n";
	}


	return 0;
}
728x90
반응형