페어 프로그래밍이 현실적으로 어렵다는 팀원들의 전체적인 의견을 따라 각자 풀고 리뷰해 주기로 결정,
java 백준 2839 설탕 배달 https://www.acmicpc.net/problem/2839
java 언어로 문제를 풀려고 앉은 나는 그냥 greedy 하게 5kg 설탕봉지가 많은 경우부터 탐색해서 n kg을 만들기를 성공하면 바로 return해야겠다는 생각이 들었는데, 과거의 나의 풀이가 심상치 않다.
[4달전 cpp 풀이]
#include <string>
#include <iostream>
#include <sstream>
using namespace std;
int main(){
int n;
cin >> n;
//3kg와 5kg를 만드는 가장 최소의 봉지수는 1
//따라서 dp[3]과 dp[5]는 무조건 1
int *dp = new int[n+1]{-1};
dp[3] = dp[5] = 1;
//3과 5 다음인 6부터 for loop 순회
for (int i = 6; i <= n; i++) {
if (dp[i - 3]) dp[i] = dp[i - 3] + 1;
//이미 dp[i-3]에 값이 존재할때 dp[i]가 업데이트 됐었을 수 있다.
//만약 dp[i]에 값이 없다면 dp[i] = dp[i-5] +1 로 업데이트
if (dp[i - 5]) dp[i] = dp[i] ? min(dp[i] , dp[i - 5] + 1) : dp[i - 5] + 1;
}
cout << (dp[n] == 0 ? -1 : dp[n]) << endl;
return 0;
}
다이나믹 프로그래밍으로 이 문제를 풀려고 하다니.. 논리는 그래도 봐줄 만 하긴 한데, 홍대병 걸린 코드 같다.
**** java 코드에서 등장하는 scan 인스턴스는 BufferedReader와 StringTokenizer를 적절히 활용해서 새로 만든 입출력 담당 클래스의 인스턴스이며 print() 메서드는 이를 활용한 겁니다. 문제와 관련 없어 첨부하지 않음*
[현재 java 풀이]
static void input(){
int n = scan.nextInt();
// 가능한 5 봉지의 개수는 n/5개
int maxPack5 = n/5;
for(int i = maxPack5; i >=0 ; i--){
int remain = n - (i * 5);
if(remain % 3 == 0){
int pack3 = remain/3;
System.out.println(i + pack3);
return;
}
}
System.out.println(-1);
}
오히려 이쪽이 더 빠르고 간결하고 가독성이 좋은 풀이 같다. 한창 dp 풀 때라서 신나게 풀었을 수도,,
만약 문제가 모든 무게에 대해서 가능한지 여부와 가능한 최소의 설탕 봉지 개수를 원했다면 dp로 풀어야 하긴 할 것 같다.
java 백준 4948 베르트랑 공준 https://www.acmicpc.net/problem/4948
소수 찾기 유형의 문제인데, 문제를 읽어보면 알겠지만 각 테스트 케이스마다 각각의 답을 출력해야 하는 문제로, 테스트 케이스가 최대 몇 갠지 알려줬어야 하지 않나 하는 생각…
왜냐면 테케가 아주 많은 경우의 수를 생각하지 못하고 아래처럼 풀었다가 시간초과가 났다.
//에라토스테네스의 체
//넓은 범위의 수 중 소수가 몇개인지 - > 에라토스테네스의 체
for(int i= 2 ; i < n; i++){
if(n % i == 0)
return false;
// [0,0,2,3,0,5,0,7,0,0,0,11,
// 100000
static int sieveOfEratosthenes(int n){
int[] arr =new int[n];
for(int i = 0 ; i < n;i++){
arr[i] = i+n+1;
}
// arr 0 1 2 3 4 5
// 100001 100002
//제곱근 까지만
double root = Math.pow((n * 2), 0.5);
for(int i = 0 ; i < n ; i++) // *n
for(int divisor = 2 ; divisor <= root; divisor++) // * root n
if(arr[i] % divisor == 0)
arr[i] = 0;
int primeCount = 0;
for(int i = 0; i < n ; i++)
if(arr[i] > 0) primeCount ++;
return primeCount;
}
static void input() throws Exception{
int n;
while(true){
n = scan.nextInt();
if(n==0)
break;
sb.append(sieveOfEratosthenes(n) + "\\n");
}
print();
}
1 ≤ n ≤123,456 에 대하여 아래와 같은 극한의 테스트 케이스가 있을 수도 있고,
123,456
123,456
123,456
123,456
123,456
123,456
123,456
123,456
123,456
123,456
123,456
123,456
0
$$n\sqrt n $$ 의 시간복잡도의 코드를 n = 100000으로 돌리면 1억 회의 연산이 필요한데,
테스트케이스가 20개만 있어도 시간초과가 날 것이 뻔했다.
따라서 어차피 변하지 않을 소수 리스트를 문제가 요구하는 최대 범위까지 미리 구해놓고
요구하는 범위에 대해서 소수를 카운트해서 출력하기로 함
그리고, 2,3,5,7 등의 소수가 2,3,5,7로 나누어지기 때문에 소수가 아닌 것으로 잘못 분류되는 오류가 있어 나누는 수와 피연산자가 같지는 않은데 나누어 떨어지는 경우 소수로 분류하는 것으로 수정했다.
static void input() throws Exception{
//원래 소수인지 파악할때는 어떤 수의 제곱근까지만 나누어떨어지는지 검사해보면 된다.
// 에라토스테네스의 체 구현
int maxLen = 123456 * 2 + 1;
int[] arr =new int[maxLen];
for(int i = 1 ; i < maxLen;i++){
arr[i] = i;
}
double root = Math.pow(maxLen, 0.5);
for(int i = 0 ; i < maxLen ; i++)
for(int divisor = 2 ; divisor <= root; divisor++)
if(arr[i] != divisor && arr[i] % divisor == 0)
arr[i] = 0;
int n = -1;
while(true){
int primeCount = 0;
n= scan.nextInt();
if(n==0)
break;
for(int i = n+1; i <= 2*n ; i++)
if(arr[i] > 0) primeCount ++;
sb.append(primeCount + "\\n");
}
print();
}
java 백준 2869 달팽이는 올라가고 싶다 https://www.acmicpc.net/problem/2869
그냥 수학문제,
v=100, a=7, b=3 일 때는
하루에 4씩 이동한다고 계산했을 때, 언젠가 96미터에서 낮을 맞이하면 등반 완료이다.
오늘 92미터에서 출발한다면, 낮에 99, 밤에 96이 되며, 이때 96미터가 되었으므로 하루 더 지나면 등반할 것을 안다.
그러므로 등반 기준선 96에서, 하루 이동 길이 4를 나눈 몫에다가 (낮이 되어야 등반 완료가 되므로) 하루를 더하면 되는데,
조심해야 할 점이 있다.
예를 들어 v=104인 a = 7, b= 3인 경우를 생각해 보면 97미터에서 하루 더 지나면 97 + 7 = 104가 되어 등반에 성공할 것이다. 그런데 a=7, b=3 스펙으로 정확히 97미터가 될 순 없고 96미터 다음은 100미터 이므로
달팽이의 현재 위치가 97미터가 되는 것과 100미터가 되는 것을 같게 봐야 한다는 것을 알 수 있다.
다음 날 등반이 완료되는 높이가 97,98,99,100인 경우 등반 완료 까지는 25 + 1 일 이 걸릴 것을 알 수 있는데, 여기서 97,98,99는 a-b인 4로 나누었을 때 몫이 24, 100은 몫이 25가 되므로 둘을 같게 해 줄 방법이 필요한데, 바로 a-b로 나눌 때 나머지가 존재하는 경우 +1을 하는 방식으로 해결할 수 있었다.
static void input(){
int up = scan.nextInt();
int down = scan.nextInt();
int v = scan.nextInt();
// 100미터인 상황 가정
// 7미터 올라가고 3미터 내려간다면, 매일 4미터 전진하는 것과 같다.
// 따라서 오늘92, 낮 99 밤 96 내일 낮 103 일 때 멈춰야 하는데,
// 다음 날 등반이 완료되는 높이를 구하자
// number + up >= v 일때 다음 날 등반 완료
int diff = up - down;
// 등반 성공 커트라인
int success = v - up; // 100 - 7 = 93
// 92 x (93, 94, 95), 96
int days = (success / diff) + (success % diff > 0 ? 1 : 0) +1;
System.out.println(days);
}