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

코드설명

완전탐색(BruteForce) + DFS(깊이우선탐색) + 동적계획법(Dynamic Programming, DP) 를 활용합니다.

 

문제를 완전탐색으로 접근했습니다. 다른 방법은 생각나지 않았습니다.

문제에서 N은 100이므로, 2^100 개의 탐색결과가 나와 시간초과가 발생할 수 있지만, 메모이제이션(Cache)를 적용하여 개선할 수 있습니다.

 

문제에서 4%에서 계속 틀렸었는데, 문제를 잘못읽었습니다.

처음에 만약 수강신청한 인원보다 과목 수강인원이 많다면, 마일리지를 0 원쓰고 들을 수 있다고 생각했습니다.

하지만, 문제에서 마일리지는 반드시 1~36 까지의 마일리지를 사용해야한다고 나옵니다.

//만약 선택한사람이 더 적다면,(수강인원이 더 많다면, 마일리지를 하나도 안쓰고 참여가능)
if(L[level] > arr[level].length) return selectCache[level] = 1;

 

코드

정답코드입니다.

package Main;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collections;
import java.util.StringTokenizer;

public class Main {
    private static int N, T, K, M;
    private static int[][] arr;
    private static int[] L;
    private static int[][] cache;
    private static int[] selectCache;
    public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());
		
		cache = new int[N+1][M+1];
		selectCache = new int[N+1];
		Arrays.fill(selectCache, -1);
		for(int i=0;i<=N;i++) {
			Arrays.fill(cache[i], -1);
		}
		arr = new int[N][];
		L = new int[N];
		for(int i=0;i<N;i++) {
			st = new StringTokenizer(br.readLine());
			int P = Integer.parseInt(st.nextToken());
			L[i] = Integer.parseInt(st.nextToken());
			arr[i] = new int[P];

			st = new StringTokenizer(br.readLine());
			for(int j=0;j<P;j++) {
				arr[i][j] = Integer.parseInt(st.nextToken());
			}
			Arrays.sort(arr[i]);
		}
		
		System.out.println(func(0, M));
		
    }
    
    private static int func(int level, int mile) {
    	if(level == N) {
    		return 0;
    	}

    	if(cache[level][mile] != -1) return cache[level][mile];
    	
    	int ret = 0;
    	//선택안할경우
    	ret = Math.max(ret, func(level + 1, mile) + 0);
    	
    	//선택할경우
    	int cost = calculateCost(level);
    	if(mile - cost >= 0) {
//    		System.out.println("level:"+level+"cost:"+cost);
    		ret = Math.max(ret, func(level + 1, mile-cost) + 1);
    	}
    	
    	return cache[level][mile] = ret;
    }
    
    private static int calculateCost(int level) {
    	if(selectCache[level] != -1) return selectCache[level];
    	//만약 선택한사람이 더 적다면,(수강인원이 더 많다면, 마일리지를 하나도 안쓰고 참여가능)
    	if(L[level] > arr[level].length) return selectCache[level] = 1;
    	
    	int cnt = 0;
    	int cost = 0;
    	for(int i=arr[level].length - 1;i>=0;i--) {
    		cnt += 1;
    		if(L[level] == cnt) {
    			cost = arr[level][i];
    			break;
    		}
    	}
    	return selectCache[level] = cost;
    }
    
    
}

처음에 시간초과 난 코드였다가 DP를 적용해서 시간초과를 해결했으나 4%에서 틀립니다.

package Main;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collections;
import java.util.StringTokenizer;

public class Main {
    private static int N, T, K, M;
    private static int[][] arr;
    private static int[] L;
    private static int[][] cache;
    public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());
		
		cache = new int[N+1][M+1];
		for(int i=0;i<=N;i++) {
			Arrays.fill(cache[i], -1);
		}
		arr = new int[N][];
		L = new int[N];
		for(int i=0;i<N;i++) {
			st = new StringTokenizer(br.readLine());
			int P = Integer.parseInt(st.nextToken());
			L[i] = Integer.parseInt(st.nextToken());
			arr[i] = new int[P];

			st = new StringTokenizer(br.readLine());
			for(int j=0;j<P;j++) {
				arr[i][j] = Integer.parseInt(st.nextToken());
			}
			Arrays.sort(arr[i]);
		}
		
		System.out.println(func(0, M));
		
    }
    
    private static int func(int level, int mile) {
    	if(level == N) {
    		return 0;
    	}

    	if(cache[level][mile] != -1) return cache[level][mile];
    	
    	int ret = 0;
    	//선택안할경우
    	ret = Math.max(ret, func(level + 1, mile) + 0);
    	
    	//선택할경우
    	int cost = greedySelect(level);
    	if(mile - cost >= 0) {
    		ret = Math.max(ret, func(level + 1, mile-cost) + 1);
    	}
    	
    	return cache[level][mile] = ret;
    }
    
    private static int greedySelect(int level) {
    	//만약 선택한사람이 더 적다면,
    	if(L[level] > arr[level].length) return 0;
    	
    	int cnt = 0;
    	int cost = 0;
    	for(int i=arr[level].length - 1;i>=0;i--) {
    		cnt += 1;
    		if(L[level] == cnt) {
    			cost = arr[level][i];
    			break;
    		}
    	}
    	return cost;
    }
    
    
}

+ Recent posts