본문 바로가기

알고리즘/백준

백준 2831 댄스파티

728x90

 

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

 

2831번: 댄스 파티

문제 남자 N명과 여자 N명이 상근이가 주최한 댄스 파티에 왔다. 상근이는 모든 사람의 키를 알고있다. 각 남자는 모두 여자와 춤을 출 수 있고, 여자는 남자와 춤을 출 수 있다. 모든 사람은 많아야 한 사람과 춤을 출 수 있다. 모든 남자는 자신이 선호하는 여자와 춤을 추려고 한다. 각 남자가 선호하는 여자는 두 가지 유형이 있는데, 한 유형은 자신보다 키가 큰 여자이고, 다른 유형은 자신보다 키가 작은 유형이다. 여자도 남자와 마찬가지로 자신이 선호하

www.acmicpc.net

 

1. 기본 조건

- 키가 -인 남자(자기보다 키가 작은 여자를 원하는 남자) 는 항상 키가 + 인여자(자기보다 키가 큰 남자를 원하는 여자)와 매칭된다.

- 키가 + 인 남자, 키가 -인 여자도 마찬가지 이유로 서로 매칭된다.

 

2. 또한, 커플쌍을 최대로 하기 위해서는

키가 + 인 여자는 자기보다 키가 큰 남자중 가장 작은 남자와 매칭되야한다.

 

예제를 통해 알아보자

 

7
-1900 -2000 -2500 1500 1600 2500 -2500  //남자
1700 1800 2200 -1550 2100 -2500 -1700 //여자

 

이중에서 남자 (-) 여자 (+)인경우만 그림으로 표현하면 다음과 같다.

-  1700여는 -1900 -2000 -2500 -2500인 남자를 모두 만날수있지만, 최대 쌍을 만드는건 1700여자가 1900인 남자와 이어지는 경우이다 즉, 자기보다 키가 큰 남자 중 가장 작은 남자를 선택하는 것이다.(이를 다른말로 upper_bound라고도 부른다.) 그 이유는 자명하다. 1700이 여자중에서 키가 제일 작기 때문에, 다른 여자들보다 항상 선택권이 많거나 같기 때문이다. 즉 다른 여자들이 자기보다 키가 작아서 못 고를수도 있는 가능성이 있는 남자를 고르는 것이다.

 

- 1800입장에서도 가장 최대의 경우는 자기보다 키가 큰 남자중 가장 작은 남자 1900을 고르는 것이 최대경우지만

앞의 1700이 먼저 1900을 골랐기 때문에 2000을 골라야한다. 즉, 중복되는 선택을 막기 위해서 원소를 삭제하거나 방문처리를 해야한다.

 

위 두 가지 조건 모두를 만족하는 자료구조는 우선순위큐다.

우선순위큐는 upperbound를 구할수 있는 순서가 있는 자료구조이며, 삭제가 O(logN)시간에 이루어진다.(JAVA의 ArrayList나 C++의 vector 삭제에 O(N)시간이 걸리기 때문에 시간초과가 발생한다.)

 

알고리즘은 다음과 같다.

while(!b0.isEmpty()&&!g1.isEmpty()) { //b0 는 자기보다 작은 g1를 만나고 싶어하는 상황
    int b = b0.poll();
    int g =g1.peek();
    if(g<b) {
    	answer++;
		g1.poll();
	}
}

1. b의 앞원소와 g의 앞원소를 비교한다.

2-1 b>g이면 가능한 경우수이므로 answer 증가 g와b의 앞원소 제거

2-2 아니면 b의 앞원소만 제거

3. b0,g1 둘중하나가 비기 전까지반복

 

반대경우에도 똑같이 적용하면된다.

 

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

public class Main{
	public static class MyScanner {
		BufferedReader bf;
		StringTokenizer st;

		MyScanner() {
			bf = new BufferedReader(new InputStreamReader(System.in));
		}

		String next() {
			while (st == null || !st.hasMoreTokens()) {
				try {
					st = new StringTokenizer(bf.readLine());
				} catch (Exception e) {
					e.printStackTrace();
				}

			}
			return st.nextToken();
		}

		public int nextInt() {
			return Integer.parseInt(next());
		}

		public long nextLong() {
			return Long.parseLong(next());
		}
	}

	public static void main(String[] args) {
		MyScanner sc = new MyScanner();
		int N = sc.nextInt();

		PriorityQueue<Integer> g1 = new PriorityQueue<Integer>();
		PriorityQueue<Integer> g0 = new PriorityQueue<Integer>();
		PriorityQueue<Integer> b1 = new PriorityQueue<Integer>();
		PriorityQueue<Integer> b0 = new PriorityQueue<Integer>();

		for (int i = 0; i < N; i++) {
			int x = sc.nextInt();
			if (x < 0)
				b0.add(-x);
			else
				b1.add(x);
		}

		for (int i = 0; i < N; i++) {
			int x = sc.nextInt();
			if (x < 0)
				g0.add(-x);
			else
				g1.add(x);
		}

		int answer = 0;

		while (!b0.isEmpty() && !g1.isEmpty()) { // b0 는 자기뵈다 작은 g 만나고 싶어함
			int b = b0.poll();
			int g = 987654321;
			g = g1.peek();
			if (g < b) {
				answer++;
				g1.poll();
			}
		}
		while (!g0.isEmpty() && !b1.isEmpty()) { // b0 는 자기뵈다 작은 g 만나고 싶어함
			int g = g0.poll();
			int b = b1.peek();
			if (g > b) {
				answer++;
				b1.poll();
			}
		}
		System.out.println(answer);

	}

}

 

P.S ArrayList로 처음에 풀다가 삭제하는 부분때문에 계속 시간초과나서 우선순위큐로 바꿨음

'알고리즘 > 백준' 카테고리의 다른 글

백준 1669멍멍이 쓰다듬기  (0) 2020.04.23
백준 18808 스티커 붙이기  (0) 2020.04.19
백준 18809 Gaaaaarden  (0) 2020.04.19
백준 2931 가스관  (0) 2020.04.15
백준 12784 인하니카 공화국  (0) 2020.04.14