하................
어렵지 않은 문제인데 제가 허튼짓을 해서 한참 걸린 문제입니다.
Case #1: 이렇게 출력해야 하는데
CASE #1: 이렇게 출력하고 있었네요.....
맞왜틀 40분 동안 하다가 찾아서 고쳐서 맞았습니다.

문제를 일단 보시면 저렇게 무작위로 섞여있는 문자열에서
zero one two three four five six seven eight nine 이 몇 개 들어있는지 찾으면 되는 문제입니다.

잘 보시면 각 단어에 하나밖에 없는 알파벳이 있습니다.
예를 들면
zero에서 z는 0~9에서 유일하죠 ?
four에서 u도 유일합니다.

제가 푼 방법은
1. 알파벳의 개수를 전부 더한 다음에
2. (0으로 예를 들면) z 1개당 z, e, r, o를 각각 하나씩 빼주고
3. brr[0]에 1을 더합니다.
이런 식으로 0, 4, 5, 7 . . . . 순으로 지워줬습니다.
숫자 4 다음에 5를 f로 찾을 수 있는 이유는 4에서 5를 제외한 f가 전부 삭제되었으니 남은 f는 five에서의 f 뿐이겠죠?


마지막에 brr[0] ~ brr[9]까지 배열 안에 더해진 숫자만큼 해당 숫자를 출력해주면 됩니다.
정말 생각도, 코딩으로 구현도 제대로 했지만 출력할 때 오타 때문에 시간 정말 오래 소비했습니다.
여러분은 그럴 일 없겠지만 절대 저 같은 실수 하지 마세요!
참 부끄럽네요...

마지막으로 반례 남기겠습니다.

3
VVVFFFIIIEEEOONEZER
OONEZER
OWT    

Case #1: 01555
Case #2: 01
Case #3: 2
2
VVVFFFIIIEEEOONEZERVVVFFFIIIEEEOONEZERVVVFFFIIIEEEOONEZERVVVFFFIIIEEEOONEZERVVVFFFIIIEEEOONEZER
NOE

Case #1: 0000011111555555555555555
Case #2: 1
2
NNNNNNNNNNEEEEEEIIIIOO
OOIIIIEEEEEENNNNNNNNNN
Case #1: 119999
Case #2: 119999
2 
INNEINNEIINNEENNNNEEOO 
WTO 
Case #1: 119999 
Case #2: 2

제가 해봤던 반례들입니다.
모두 화이팅

#include <stdio.h>
#include <string.h>
int main() {
    int t;
    char s[2000] = {};
    int arr[100] = {}, brr[10] = {};
    scanf("%d", &t);
    for(int i = 0; i < t; i++) {
        scanf("%s", s);
        for(int i = 0; i < strlen(s); i++) {
            char temp = s[i];
            arr[temp]++;
        }
            while(arr['Z'] > 0) {
                brr[0]++;
                arr['Z']--;
                arr['E']--;
                arr['R']--;
                arr['O']--;

            }
            while(arr['U'] > 0) {
                brr[4]++;
                arr['F']--;
                arr['O']--;
                arr['U']--;
                arr['R']--;
            }
            while(arr['F'] > 0) {
                brr[5]++;
                arr['F']--;
                arr['I']--;
                arr['V']--;
                arr['E']--;
            }
            while(arr['V'] > 0) {
                brr[7]++;
                arr['S']--;
                arr['E']--;
                arr['E']--;
                arr['V']--;
                arr['N']--;
            }
            while(arr['X'] > 0) {
                brr[6]++;
                arr['S']--;
                arr['I']--;
                arr['X']--;
            }
            while(arr['W'] > 0) {
                brr[2]++;
                arr['T']--;
                arr['W']--;
                arr['O']--;
            }
            while(arr['G'] > 0) {
                brr[8]++;
                arr['E']--;
                arr['I']--;
                arr['G']--;
                arr['H']--;
                arr['T']--;
            }
            while(arr['H'] > 0) {
                brr[3]++;
                arr['T']--;
                arr['E']--;
                arr['H']--;
                arr['R']--;
                arr['E']--;
            }
            while(arr['I'] > 0) {
                brr[9]++;
                arr['N']--;
                arr['I']--;
                arr['N']--;
                arr['E']--;
            }
            while(arr['O'] > 0) {
                brr[1]++;
                arr['O']--;
                arr['E']--;
                arr['N']--;
            }
            printf("Case #%d: ", i+1);
            for(int i = 0; i < 10; i++) {
                while(brr[i] > 0) {
                    printf("%d", i);
                    brr[i]--;
                }
            }
            printf("\n");
    }
}

문제 링크

평범한 rgb거리 문제에서 첫 번째 집과 마지막 집이 같은 색이면 안 된다는 조건이 추가된 문제입니다.

 

그래서 예제 1번을 보시면 원래의 최솟값은 26  57 13을 선택했을 때의 96이지만,

1번 집과 3번 집의 색이 다른 40 57 13 을 골랐을 때의 110이 출력되는 모습을 볼 수 있습니다.

 

저는 간단하게 생각해서 살짝 코드가 더럽지만 아주 쉽게 풀었습니다!

바로 1번 집과 2번 집에는 같은 색이 불가능하다는 것을 이용했는데요.

위의 상황을 생각해보면, 1번 집에서 빨강을 골랐을 경우 2번 집의 빨강 비용을 100만으로 바꿔주고(이렇게 하면 2번 집이 빨강인 경우 최솟값이 될 수가 없습니다.)  초록, 파랑에는 1번 집의 빨강 비용을 더해준 후 일반적인 rgb거리 1번 문제를 풀듯이 풀었습니다.

마지막에 총 비용을 계산할 땐 n번째 집이 빨강인 경우를 제외하고 나머지 2가지 중 최솟값을 구해주면 되죠.

 

그래서 저는 dp1 dp2 dp3 배열 3가지를 준비해서

각각 1번 집이 빨강, 초록, 파랑인 경우의 총비용. 그러니까 3 * 2 = 6가지의 값 중 최솟값을 찾아서 출력시켰더니 정답을 받았습니다.

 

밑의 주석에 설명 달아놨습니다.

#include <stdio.h>
#define min(x, y) ((x) < (y) ? (x) : (y))

int main() {
    int arr[1002][3], n;
    int dp1[1002][3], dp2[1002][3], dp3[1002][3];
    scanf("%d", &n);
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < 3; j++) {
            scanf("%d", &arr[i][j]);
        }
    }
    dp1[1][0] = 1000000; //1번 집이 빨강인 경우 2번 집 빨강 비용은 백만
    dp1[1][1] = arr[0][0] + arr[1][1];
    dp1[1][2] = arr[0][0] + arr[1][2];
    dp2[1][1] = 1000000; //1번 집이 초록인 경우 2번 집 초록 비용은 백만
    dp2[1][0] = arr[0][1] + arr[1][0];
    dp2[1][2] = arr[0][1] + arr[1][2];
    dp3[1][2] = 1000000; //1번 집이 파랑인 경우 2번 집 파랑 비용은 백만
    dp3[1][1] = arr[0][2] + arr[1][1];
    dp3[1][0] = arr[0][2] + arr[1][0];        
    for(int i = 2; i < n; i++) {
       dp1[i][0] = min(dp1[i - 1][1], dp1[i-1][2]) +arr[i][0];
       dp1[i][1] = min(dp1[i - 1][0], dp1[i-1][2]) +arr[i][1];
       dp1[i][2] = min(dp1[i - 1][0], dp1[i-1][1]) +arr[i][2];
       dp2[i][0] = min(dp2[i - 1][1], dp2[i-1][2]) +arr[i][0];
       dp2[i][1] = min(dp2[i - 1][0], dp2[i-1][2]) +arr[i][1];
       dp2[i][2] = min(dp2[i - 1][0], dp2[i-1][1]) +arr[i][2];
       dp3[i][2] = min(dp3[i - 1][0], dp3[i-1][1]) +arr[i][2];              
       dp3[i][0] = min(dp3[i - 1][1], dp3[i-1][2]) +arr[i][0];
       dp3[i][1] = min(dp3[i - 1][0], dp3[i-1][2]) +arr[i][1];
    }

    int a = min(dp1[n-1][1], dp1[n-1][2]); //1번 집이 빨강이니까 n번 집이 초록, 파랑인 경우만 생각
    int b = min(dp2[n-1][0], dp2[n-1][2]);
    int c = min(dp3[n-1][0], dp3[n-1][1]);
    printf("%d", a < b ? (a < c ? a : c) : (b < c ? b : c)); // a, b, c 중 최솟값 구하기
}

 

https://www.acmicpc.net/problem/1484

 

1484번: 다이어트

성원이는 다이어트를 시도중이다. 성원이는 정말 정말 무겁기 때문에, 저울이 부셔졌다. 성원이의 힘겨운 다이어트 시도를 보고만 있던 엔토피아는 성원이에게 새로운 저울을 선물해 주었다.

www.acmicpc.net

연속되는 두 수의 제곱의 차 중 10만에 제일 가까우면서 10만보다는 작은 것이 50000 ^ 2 - 49999 ^ 2가 99999였습니다.
그래서 5만까지 배열에 넣어줬습니다.

투포인터를 사용해서 현재 몸무게 - 기억하고 있는 몸무게를 전부 확인해서 출력해줬구요, 가장 중요한 것은 ll에 주의하라고 적어놓은 두 부분입니다. 배열은 미리 알고 long long으로 해뒀는데, 밑에 'll에 주의하세요 2번'을 보시면 arr[i] = i * i에서 i가 long long이 아니고 int일 시에 정수 오버플로우가 나더라고요. 지금 생각해보니까 당연한 것 같긴 한데, 문제 풀 땐 아무 생각이 없었습니다.
저 반복문에서 i를 int로 해두면 정수오버플로우가 나서 99999의 경우에 필요한 arr[50000]에 값을 제대로 넣어주지 못합니다.

나머지는 코드만 보셔도 다 이해할 수 있을 겁니다.

감사합니다.

#include <stdio.h>
#include <math.h>

unsigned long long arr[50001]; // ll에 주의하세요 !!!!!!!
int main() {
    int n, a = 1, b = 2, temp = 0; //temp는 가능한 몸무게가 있는지 확인하기 위함
    for(long long i = 1; i <= 50000; i++) { // ll에 주의하세요 2 !!!!!!!
        arr[i] = i * i;
    }
    scanf("%d", &n);
    for(int i = 1; i <= 100100; i++) { //100100은 의미없습니다.
        if (b > 50000) break;
        if (a == b) b++;
        if(arr[b] - arr[a] == n) {
            printf("%.f\n", sqrt(arr[b]));//배열의 값은 제곱한 상태이니 sqrt로 루트를 씌워줍니다.
            temp = 1; //한 번이라도 이 if문을 돌게되면 temp는 1
        }
        if(arr[b] - arr[a] >= n) {
            a++;
        }
        if(arr[b] - arr[a] < n) {//몸무게의 차가 n보다 작으면
            b++;//당연히 더 큰 현재의 몸무게에서 빼줘야겠죠?
        }
    }
    if(temp == 0) { // 가능한 몸무게가 없다면
        printf("-1");
    }
}

https://www.acmicpc.net/problem/1644

 

1644번: 소수의 연속합

첫째 줄에 자연수 N이 주어진다. (1 ≤ N ≤ 4,000,000)

www.acmicpc.net

안녕하세요, 골드 3을 우연찮게 풀게 됐습니다. 투포인터를 배우자마자 처음으로 푼 문제입니다.

연속합 문제라 투포인터를 사용하면 쉽게 풀 수 있는 문제인데, 에라토스테네스의 체를 사용해야 합니다. 

왜냐면 소수의 연속합 문제이기 때문이죠. 

 

에라토스테네스의 체는 예전에 풀어봐서 구현은 쉽게 했습니다.

하지만 문제가 있었습니다. N이 400만이었기 때문인데요, 지역 변수로 400만개짜리 배열을 선언했더니 zsh segmentation fault였나? 오류가 떴습니다. 100만 정도까진 괜찮았는데 좀 커지면 계속 오류가 뜨더라고요.

그래서 전역 변수로 배열을 선언해줌으로써 문제를 해결했습니다. 하지만 고작 그것 하나 해결하는 데에 20분 가까이 썼다는 점이 아쉬웠습니다.

 

하지만 지식을 얻었다는 것.

그렇다면 오케이겠죠?

 

brr의 사이즈가 283148인 이유는 1~400만 사이의 소수의 개수가 283148개였나? 그쯤이길래 저렇게 했습니다.

 

#include <stdio.h>
#include <math.h>

#define S 4000001 //배열 크기
int arr[S] = {0};

int main(void) {
    int brr[283148];
    int n = 1, N;
    int a = 1, b = 2, temp, answer = 0;
    scanf("%d", &N);

    for(int i = 2; i < sqrt(S); i++) { //에라토스테네스의 체
        if(arr[i] != 1) {
            for(int j = 2; i * j < S; j++) {
                arr[i * j] = 1;
            }
        }
    }
    for(int i = 2; i <= S; i++) { //소수를 brr로 옮기기
        if(arr[i] != 1) {
            brr[n] = i;
            n++;
        }
    }
    temp = brr[1];
    for(int i = 1; i < 283148 * 2; i++) { //여기서부터 투포인터 입니다.
        if (temp < N) {
            temp += brr[b];
            b++;     
        }
        else if(temp > N) {
            temp -= brr[a];
            a++;    
        }
        else if(temp == N) {
            answer++;
            temp += brr[b];
            b++;   
        }
        if(brr[b - 1] > N) break;
    }
    printf("%d", answer);
}

400만을 여러 번 적으려니까 귀찮아져서 define 사용해봤습니다. 

하하하 감사합니다

+ Recent posts