[SWEA 4012] 요리사

업데이트:

문제

  • SWEA 4012
  • 문제의 저작권은 SW Expert Academy에 있습니다.

접근방식

음식A,B를 N/2개씩 나누는것에서 출발하기 때문에 음식A를 만들게 되면 그 나머지는 B가 된다.
따라서, 음식A를 N/2개 만드는 조합을 재귀를 돌면서 selcted[]에 true표시하고, 자연스럽게 결정된 음식B와 함께 각각의 음식의 맛을 구한다. 현재 조합에서의 음식A와 B 각각의 음식의 맛은 totalA, totalB로 관리한다. 음식의 맛은 음식 2개의 시너지의 합이기 때문에 for문으로 모든 식재료를 돌면서 만약 selected[i] == true이면 음식A에 해당하는 식재료가 되고, 그 다음 음식A에 해당하는 식재료를 뽑아서 totalA에 저장한다. B도 마찬가지로 !selected[i] == true인 식재료를 2개 뽑아서 totalB에 저장한다. 이를 모두 반복해서 A의 음식의 맛과 B의 음식의 맛의 차의 절대값을 구하고 기존의 정답이 되는 Ans와 비교해 더 작으면 Ans에 저장해준다.

코드

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

//요리사
public class Solution {

	static int N; //식재료 수
	static int[][] table; //음식 시너지 정보, 1번부터 시작
	static boolean[] selected; //현재 뽑힌 음식A의 조합
	static int Ans; //정답: 최종 결정된 음식의 맛

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int T = Integer.parseInt(br.readLine()); // 테스트케이스의 개수
		StringTokenizer st;

		for (int tc = 1; tc <= T; tc++) {
			N = Integer.parseInt(br.readLine()); 
			Ans = Integer.MAX_VALUE; //최대값으로 초기화
			table = new int[N+1][N+1]; //1~N
			for(int i=1; i<=N; i++) {
				st = new StringTokenizer(br.readLine());
				for(int j=1; j<=N; j++) {
					table[i][j] = Integer.parseInt(st.nextToken());
				}
			}
			
			selected = new boolean[N+1];
			//N/2개씩 음식A의 조합을 먼저 만들자 => 뽑고안뽑고 조합 사용!
			select(1, 0);
			System.out.println("#"+tc+" "+Ans);
		}
	}

	//selected배열에서 true인 식재료가 음식A임
	private static void select(int idx, int cnt) {
		
		if(cnt == N/2) { //N/2번 뽑았다면
			//현재 조합에서의 A,B의 음식의 맛 구하기, 1->2,2->1도 고려해야함
			int totalA = 0, totalB = 0; //A,B의 음식의 맛: 시너지들의 합
			
			//음식A의 식재료를 돌면서 두개를 뽑아 시너지를 누적합해서 음식의 맛 구하기
			for(int i=1; i<=N; i++) {
				if(selected[i]) { //음식A의 식재료라면
					for(int j=1; j<=N; j++) {
						if(selected[j]) { //또 다른 음식A의 식재료라면 
							totalA += table[i][j];
						}
					}
				}
				
				if(!selected[i]) { //음식B의 식재료라면
					for(int j=1; j<=N; j++) {
						if(!selected[j]) { //또 다른 음식B의 식재료라면
							totalB += table[i][j];
						}
					}
				}
			}
			Ans = Math.min(Ans, Math.abs(totalA - totalB));
		}
	
		if(idx == N) { //안뽑았는데 너무 많이 와버렸다면
			return;
		}
		
		selected[idx] = true; //뽑고
		select(idx+1, cnt+1); //뽑았음
		selected[idx] = false; //안뽑았음
		select(idx+1, cnt);
	}
}