BOJ - USC Spring 2019

문제들(링크)

영어로 된 문제 세트들입니다.
ICPC 같은 국제대회에선 거의 모든 문제가 영어로 출제되기에 감을 익혀볼 겸 풀어보는 것도 좋은 것 같습니다.

A번 - Cap Size(17659번)

0부터 1000 사이의 모자 크기를 주고, 주인공에게 딱 맞거나 맞을 것 같은 모자의 개수를 찾는 문제입니다.
모자의 크기와 숫자가 주어지는데, 의미는 다음과 같습니다.

숫자가 1 -> 주인공의 머리가 그 모자보다 크다.
숫자가 0 -> 딱 맞는 모자이다.(단, 딱 맞는 모자는 이 모자밖에 없습니다.)
숫자가 -1 -> 주인공의 머리가 그 모자보다 작다.

capSize[1001] 의 배열을 선언하고 1과 -1 사이의 모자 개수를 세주면 됩니다.
단, 논리적으로 말이 안되는 입력이면 "Inconsistent feedback" 을 출력해야 하는데, 
예외 상황이 좀 많습니다.

1. 숫자 0이 각각 다른 모자에 주어질 때 -> 딱 맞는 모자는 하나 뿐
2. 숫자가 이미 주어졌는데 다른 숫자가 또 주어질 때
3. 숫자 0이 주어진 모자보다 큰 모자가 1을 가질 때
4. 숫자 0이 주어진 모자보다 작은 모자가 -1을 가질 때
5. -1이 1 보다 앞에 올 때
6. 같은 모자에 같은 숫자가 계속 주어질 때 -> 맞는 입력입니다.





코드

import java.io.*;
import java.util.*;

public class Main {

    public static int N, T;

    public static void main(String[] argc) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        int K = Integer.parseInt(br.readLine());

        for (int i = 0; i < K ; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            N = Integer.parseInt(st.nextToken());
            T = Integer.parseInt(st.nextToken());

            int[] capSize = new int[1001];
            Arrays.fill(capSize, -2);

            st = new StringTokenizer(br.readLine());
            for (int j = 1; j <= N ; j++) {
                capSize[Integer.parseInt(st.nextToken())] = 2;
            }

            boolean impo = false;
            int cnt = 0;
            int p_idx = 0;
            for (int j = 0; j < T ; j++) {
                st = new StringTokenizer(br.readLine());
                int c = Integer.parseInt(st.nextToken());
                int f = Integer.parseInt(st.nextToken());

                if(capSize[c] == 2)
                    capSize[c] = f;
                else if(capSize[c] == f)
                    continue;
                else
                    impo = true;
            }
            bw.write("Data Set " + (i + 1) + ":\n");

            if(!impo) {
                int largeIdx = -1;
                int smallIdx = 1001;
                int fit_cnt = 0;

                for (int j = 0; j <= 1000; j++) {
                    if(capSize[j] == 1)
                        largeIdx = Math.max(largeIdx, j);
                    if(capSize[j] == -1)
                        smallIdx = Math.min(smallIdx, j);
                    if(capSize[j] == 0) {
                        fit_cnt++;
                        p_idx = j;
                    }
                }

                if(fit_cnt == 0) {

                    if(largeIdx < smallIdx){
                        for (int j = largeIdx + 1; j < smallIdx ; j++) {
                            if(capSize[j] == -2)    continue;
                            cnt++;
                        }
                    }
                    else
                        impo = true;
                }
                else if(fit_cnt == 1){
                    cnt = 1;
                    if(p_idx >= smallIdx || p_idx <= largeIdx)
                        impo = true;
                }
                else
                    impo = true;

                if(!impo)
                    bw.write(cnt + "\n\n");
                else
                    bw.write("Inconsistent feedback\n\n");
            }
            else
                bw.write("Inconsistent feedback\n\n");
        }
        bw.flush();
        bw.close();
    }
}


B번 - First-Name Basis(17660번)

여러 개의 first 이름과 second 이름이 주어졌을 때, first 이름은 first 이름으로만, second 이름은 second 이름으로만 사용되게끔 이름을 반전시켜 주어야 하는데, 이 때 최소한의 반전 횟수를 구하는 문제입니다.

즉,
5
a b
a c
c d
d d
d e
입력의 정답은 (a , b) , (a , c) 두 세트를 반전시켜주면 되기 때문에 2입니다.

풀이 코드는 http://contest.usc.edu/index.php/Main/Spring2019USCProgrammingContest?action=download&upname=sp19.first.hemant.java.txt 를 참고했습니다.

입력이 String으로 들어오기 때문에 HashMap 을 이용했고, 이분 그래프를 만들기 위해 입력값들을 양방향 그래프로 이어 주었습니다.
위의 입력은 다음과 같습니다.(양방향 그래프이기때문에 방향은 표시하지 않았습니다.)
이제 위 그래프를 이분 그래프로 바꾸어 색칠하면 다음과 같습니다.
이제 위 이분 그래프에서 정답을 어떻게 찾느냐가 문제인데, 먼저 이분 그래프를 만들 때 "Impossible" 의 경우는 걸러지게 됩니다.("Impossible" 인 경우 색깔이 겹치게 됩니다.)

정답을 찾기 위해 위의 입력을 다시 사용해야 합니다.(따로 배열에 저장합니다.)
이 문제에서 정답은 결국 first 이름은 모두 빨강(or 파랑) , second 이름은 모두 파랑(or 빨강) 이 되게끔 입력값들을 반전시켜 주는 것입니다.

입력 배열을 모두 보면서, first 이름의 색깔에 따라 색의 count를 각각 증가시킵니다.
위 입력에선 a,a,c,b,b 이므로 빨강 = 2개, 파랑 = 3개가 됩니다.
즉,  빨강 2개만 반전시켜 주면(파랑으로 만들면) 최소값을 구할 수 있습니다!

단, 문제에서 하나의 그래프가 나오는게 아니라 여러개의 그래프 집합이 만들어지므로 각각의 그래프에서 위 작업을 수행한 뒤 더해주어야 합니다.






코드

import java.io.*;
import java.util.*;

public class Main {

    public static int N;
    public static ArrayList<Node> tree;
    public static HashMap<String, Integer> hm;
    public static void main(String[] argc) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        int K = Integer.parseInt(br.readLine());

        for (int i = 0; i < K ; i++) {
            bw.write("Data Set " + (i + 1) + ":\n");

            N = Integer.parseInt(br.readLine());
            tree = new ArrayList<>();
            hm = new HashMap<>();

            StringTokenizer st;
            int idx = 0;
            int[][] query = new int[N][2];

            for (int j = 0; j < N ; j++) {
                st = new StringTokenizer(br.readLine());
                String first = st.nextToken();
                String second = st.nextToken();

                if(!hm.containsKey(first)){
                    tree.add(new Node(idx));
                    hm.put(first, idx++);
                }
                if(!hm.containsKey(second)){
                    tree.add(new Node(idx));
                    hm.put(second, idx++);
                }
                int from = hm.get(first);
                int to = hm.get(second);
                query[j][0] = from;
                query[j][1] = to;

                tree.get(from).next.add(tree.get(to));
                tree.get(to).next.add(tree.get(from));
            }
            int setNum = binary();
            if(setNum == -1)
                bw.write("Impossible\n\n");
            else{
                int[][] answer = new int[setNum][2];
                //각 집합마다의 정답이 저장됩니다.

                for (int[] temp : query) {
                    //각 입력에서 첫 번째 문자의 색깔에 따라 분류해서 카운트합니다.
                    int first = temp[0];
                    if(tree.get(first).color == 0)
                        answer[tree.get(first).setNum][0]++;
                    else
                        answer[tree.get(first).setNum][1]++;
                }
                int res = 0;
                for (int[] cost : answer) {
                    res += Math.min(cost[0], cost[1]);
                }
                bw.write(res + "\n\n");
            }
        }
        bw.flush();
        bw.close();
    }
    public static int binary(){
        int set = 0;
        for (int i = 0; i < tree.size() ; i++) {
            if(tree.get(i).color != -1) continue;
            //이미 색칠된 집합이면 continue
            tree.get(i).setNum = set;
            set++;
            tree.get(i).color = 0;
            Queue<Node> q = new LinkedList<>();
            q.offer(tree.get(i));

            while(!q.isEmpty()){
                Node now = q.poll();

                for (int j = 0; j < tree.get(now.num).next.size() ; j++) {
                    Node next = tree.get(now.num).next.get(j);

                    if(now.color == next.color) return -1;
                    if(next.color != -1)    continue;
                    next.setNum = now.setNum;
                    next.color = 1 - now.color;
                    q.offer(next);
                }
            }
        }
        return set;
    }
}

class Node{
    int num;
    int setNum;
    int color = -1;
    ArrayList<Node> next;
    public Node(int num){
        this.num = num;
        next = new ArrayList<>();
    }
}

C번 - Mangling Names(17661번)

주어지는 단어마다 모음의 개수와 자음의 개수를 세고 2차원 배열에 맞게 값을 더해주면 되는 간단한 문제입니다.
2차원 배열 cost[i][j] 의 의미는 모음 i 개, 자음 j 개일 때의 값입니다.






코드

import java.io.*;
import java.util.StringTokenizer;

public class Main {

    public static int N, M;
    public static int[][] time;
    public static void main(String[] argc) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        int K = Integer.parseInt(br.readLine());

        for (int i = 0; i < K ; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());

            N = Integer.parseInt(st.nextToken());
            M = Integer.parseInt(st.nextToken());

            time = new int[N + 1][N + 1];

            for (int j = 0; j < N + 1 ; j++) {
                st = new StringTokenizer(br.readLine());
                for (int k = 0; k < N + 1 ; k++) {
                    time[j][k] = Integer.parseInt(st.nextToken());
                }
            }

            int res = 0;
            for (int j = 0; j < M ; j++) {
                String now = br.readLine();

                res += sum(now);
            }

            bw.write("Data Set " + (i + 1) + ":\n");
            bw.write(res + "\n\n");
        }
        bw.flush();
        bw.close();
    }
    public static int sum(String s){
        int vowel = 0;
        int cons = 0;

        for (int i = 0; i < s.length() ; i++) {
            if(s.charAt(i) == 'a' || s.charAt(i) == 'e' || s.charAt(i) == 'o' || s.charAt(i) == 'y' || s.charAt(i) == 'i' || s.charAt(i) == 'u')
                vowel++;
            else
                cons++;
        }
        return time[vowel][cons];
    }
}




댓글

이 블로그의 인기 게시물

HTML - input file 버튼 꾸미기

HTML - 이미지 미리보기(jQuery 없이)

BOJ - DNA 유사도(2612)