BOJ - USC Spring 2019
문제들(링크)
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개만 반전시켜 주면(파랑으로 만들면) 최소값을 구할 수 있습니다!
단, 문제에서 하나의 그래프가 나오는게 아니라 여러개의 그래프 집합이 만들어지므로 각각의 그래프에서 위 작업을 수행한 뒤 더해주어야 합니다.
C번 - Mangling Names(17661번)
주어지는 단어마다 모음의 개수와 자음의 개수를 세고 2차원 배열에 맞게 값을 더해주면 되는 간단한 문제입니다.
2차원 배열 cost[i][j] 의 의미는 모음 i 개, 자음 j 개일 때의 값입니다.
영어로 된 문제 세트들입니다.
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]; } }
댓글
댓글 쓰기