15686번: 치킨 배달

크기가 N×N인 도시가 있다. 도시는 1×1크기의 칸으로 나누어져 있다. 도시의 각 칸은 빈 칸, 치킨집, 집 중 하나이다. 도시의 칸은 (r, c)와 같은 형태로 나타내고, r행 c열 또는 위에서부터 r번째 칸

www.acmicpc.net


 

  • 코드

실패 코드 : 시간 초과 백트래킹으로 치킨 집의 수가 M일 때까지 되돌려가면서 돌려줌. 치킨 집의 수가 M이 되었을 때 모든 치킨집과 집의 거리의 수를 더해준 값을 return 해준다. return 값 중 최소 값을 출력.

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
	static int[][] array;
	static boolean[][] check;
	static ArrayList<int[]> houses;
	static int N, M, min = Integer.MAX_VALUE;

	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());
		array = new int[N + 1][N + 1];
		houses = new ArrayList<>();

		int count = 0;
		for (int i = 1; i <= N; i++) {
			st = new StringTokenizer(br.readLine());
			for (int j = 1; j <= N; j++) {
				array[i][j] = Integer.parseInt(st.nextToken());
				if (array[i][j] == 2)
					count++;
				if (array[i][j] == 1)
					houses.add(new int[] { i, j });
			}
		}

		dfs(count);
		System.out.println(min);
	}

	// 치킨 집의 수가 M일 때까지 줄임
	// DFS 재귀 형식
	private static void dfs(int count) {
		// base case (치킨 집의 개수가 M이 되었을 때)
		if (count == M) {
			min = Math.min(min, bfs());
			return;
		}

		for (int i = 1; i <= N; i++) {
			for (int j = 1; j <= N; j++) {
				if (array[i][j] == 2) {
					array[i][j] = 0;
					dfs(count - 1);
					array[i][j] = 2;
				}
			}
		}
	}

	private static int bfs() {
		// 임시 배열 (기존 배열을 유지하기 위함)
		Queue<int[]> queue = new LinkedList<>();
		for (int i = 1; i <= N; i++)
			for (int j = 1; j <= N; j++)
				if (array[i][j] == 2)
					queue.add(new int[] { i, j });

		// 벽으로 보호되지 않은 곳은 virus를 퍼뜨림
		// BFS
		int sum = 0;
		while (!queue.isEmpty()) {
			int location[] = queue.poll();

			for (int[] house : houses)
				sum += ReturnAbsoluteValue(location[0], house[0]) + ReturnAbsoluteValue(location[1], house[1]);

		}
		return sum;
	}

	private static int ReturnAbsoluteValue(int a, int b) {
		if (a > b)
			return a - b;
		else
			return b - a;
	}
}

 

 

정답 코드 : stack에 치킨집을 하나씩 push, pop해주며 stack의 개수가 M개일 때, 최소 거리를 구해줌.

 

개선 사항

백트래킹으로 제거해주면서 돌리던 부분 => stack을 통해 해당 치킨집만 스택에 push, pop하며 push한 개수가 M개 일 때 체크한 뒤 마지막 push를 pop해줌 (위의 코드에서 bfs 첫번째 for문 O(n^2) 작업을 안해도됌)

 

 

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.InputMismatchException;
import java.util.Stack;

public class Main {
    static int N, M;
    static int[][] array;
    static ArrayList<int[]> chickens;
    static ArrayList<int[]> houses;
    static Stack<int[]> selectedChicken;
    static int min;
	
    public static void main(String[] args) throws Exception {
        SetData();
        SelectChicken(0, 0);
        System.out.println(min);
    }
    
	private static void SetData() throws Exception {
		InputReader in = new InputReader(System.in);

        N = in.readInt();
        M = in.readInt();

        array = new int[N + 1][N + 1];
        min = Integer.MAX_VALUE;
        chickens = new ArrayList<>();
        houses = new ArrayList<>();
        selectedChicken = new Stack<>();

        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                array[i][j] = in.readInt();

                if (array[i][j] == 1) {
                	// 집
                    houses.add(new int[] {i, j});
                } else if (array[i][j] == 2) {
                    // 치킨집
                    chickens.add(new int[] {i, j});
                }
            }
        }
	}
	
    static void SelectChicken(int start, int count) {
    	// Basecase
        if (count == M) {
            bfs();
            return;
        }

        // 선택된 치킨집 3개를 구하기 위함.
        for (int i = start; i < chickens.size(); i++) {
        	selectedChicken.push(chickens.get(i));
            SelectChicken(i + 1, count + 1);
            selectedChicken.pop();
        }
    }

    static void bfs() {
        int sum = 0;
        for (int[] house : houses) {
            int tempMin = Integer.MAX_VALUE;
            
            // 해당 치킨집에서의 최소 배달 지역 집을 선택
            for (int[] chicken : selectedChicken) {
                int tempValue = Math.abs(house[0] - chicken[0]) + Math.abs(house[1] - chicken[1]);
                tempMin = Math.min(tempMin, tempValue);
            }
            sum += tempMin;

            // 현재까지의 값이 구하려는 최소값보다 크면 작업을 더 안해도 됨 => return
            if (sum > min) {
                return;
            }
        }
        min = Math.min(sum, min);
    }
	
	private static class InputReader {
		private InputStream stream;
		private byte[] buf = new byte[1024];
		private int curChar;
		private int numChars;
		private SpaceCharFilter filter;

		public InputReader(InputStream stream) {
			this.stream = stream;
		}

		public int read() {
			if (numChars == -1) {
				throw new InputMismatchException();
			}
			if (curChar >= numChars) {
				curChar = 0;
				try {
					numChars = stream.read(buf);
				} catch (IOException e) {
					throw new InputMismatchException();
				}
				if (numChars <= 0) {
					return -1;
				}
			}
			return buf[curChar++];
		}

		public int readInt() {
			int c = read();
			while (isSpaceChar(c)) {
				c = read();
			}
			int sgn = 1;
			if (c == '-') {
				sgn = -1;
				c = read();
			}
			int res = 0;
			do {
				if (c < '0' || c > '9') {
					throw new InputMismatchException();
				}
				res *= 10;
				res += c - '0';
				c = read();
			} while (!isSpaceChar(c));
			return res * sgn;
		}

		public boolean isSpaceChar(int c) {
			if (filter != null) {
				return filter.isSpaceChar(c);
			}
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}

		public interface SpaceCharFilter {
			public boolean isSpaceChar(int ch);
		}
	}
}

 

 

공부해볼 코드

 

/**
 * 출처 : https://www.acmicpc.net/source/16451230
 */

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

public class Main {

    private static final int HOUSE = 1;
    private static final int CHICKEN = 2;

    private static int n;
    private static int m;

    private static Point[] house;
    private static Point[] chick = new Point[13];
    private static Dist[][] distMap;

    private static int numHouse = 0;
    private static int numChicken = 0;

    private static int min = Integer.MAX_VALUE;

    public static void main(String[] args) throws Exception {
        inputData();
        solve();
    }

    private static void inputData() throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = s2i(st.nextToken());
        m = s2i(st.nextToken());

        house = new Point[2*n];

        for (int i = 0; i < n; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < n; j++) {
                int tmp = s2i(st.nextToken());

                if (tmp == HOUSE) {
                    house[numHouse++] = new Point(i, j);
                } else if (tmp == CHICKEN) {
                    chick[numChicken++] = new Point(i, j);
                }
            }
        }


    }

    private static void solve() {
        recordDistHouseFromChicken();
        dfs(distMap, 0, 0, new boolean[numChicken]);
        System.out.println(min);
    }

    private static void recordDistHouseFromChicken() {
        distMap = new Dist[numHouse][numChicken];

        for (int i = 0; i < numHouse; i++) {
            for (int j = 0; j < numChicken; j++) {
                distMap[i][j] = new Dist(j, calculateChickDist(i, j));
            }

            Arrays.parallelSort(distMap[i]);
        }
    }

    private static void dfs(Dist[][] distMap, int cnt, int idx, boolean[] checkChick) {
        if (cnt == m) {
            int sum = 0;
            for (Dist[] dists : distMap) {
                for (Dist dist : dists) {
                    if (checkChick[dist.idxChick]) {
                        sum += dist.dist;
                        break;
                    }
                }
            }

            if (sum < min) {
                min = sum;
            }
            return;
        }

        if (idx == numChicken) {
            return;
        }

        checkChick[idx] = true;
        dfs(distMap, cnt + 1, idx + 1, checkChick);
        checkChick[idx] = false;
        dfs(distMap, cnt, idx + 1, checkChick);
    }


    private static int calculateChickDist(int idxHouse, int idxChick) {
        return Math.abs(house[idxHouse].r - chick[idxChick].r) + Math.abs(house[idxHouse].c - chick[idxChick].c);
    }

    private static int s2i(String s) {
        return Integer.parseInt(s);
    }
}

class Point {
    int r, c;

    Point(int r, int c) {
        this.r = r;
        this.c = c;
    }
}

class Dist implements Comparable<Dist> {
    int idxChick, dist;

    Dist(int idxChick, int dist) {
        this.idxChick = idxChick;
        this.dist = dist;
    }

    @Override
    public int compareTo(Dist d) {
        if (this.dist == d.dist) {
            return Integer.compare(this.idxChick, d.idxChick);
        }
        return Integer.compare(this.dist, d.dist);
    }
}

 

2573번: 빙산

첫 줄에는 이차원 배열의 행의 개수와 열의 개수를 나타내는 두 정수 N과 M이 한 개의 빈칸을 사이에 두고 주어진다. N과 M은 3 이상 300 이하이다. 그 다음 N개의 줄에는 각 줄마다 배열의 각 행을

www.acmicpc.net


 

  • 생각

빙하의 덩어리 수를 계산할 때 bfs를 통해 총 몇개의 빙하로 나누어졌는지 구해준다.

 

 

  • 코드

 

import java.io.IOException;
import java.io.InputStream;
import java.util.InputMismatchException;

public class Main {
	private static int N, M;
	private static int[][] array;
	private static int[][] melt;
	private static boolean[][] check;
	private static int[] dr = { -1, 1, 0, 0 };
	private static int[] dc = { 0, 0, -1, 1 };
	
    public static void main(String[] args) throws Exception {
        SetData();
    }
    
	private static void SetData() throws Exception {
		InputReader in = new InputReader(System.in);

		N = in.readInt();
		M = in.readInt();

		array = new int[N][M];
		melt = new int[N][M];
		check = new boolean[N][M];

		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				array[i][j] = in.readInt();
			}
		}

		int year = 0;
		while (true) {
			int cnt = 0;
			for (int r = 0; r < N; r++) {
				for (int c = 0; c < M; c++) {
					if (array[r][c] != 0 && !check[r][c]) {
						dfs(r, c);
						cnt++;
					}
				}
			}

			if (cnt == 0) {
				System.out.println(0);
				return;
			} else if (cnt >= 2) {
				System.out.println(year);
				return;
			}

			melting();
			year++;
		}
	}
	
	private static void dfs(int r, int c) {
		check[r][c] = true;
		for (int i = 0; i < 4; i++) {
			int nr = r + dr[i];
			int nc = c + dc[i];
			if (nr >= 0 && nr < N && nc >= 0 && nc < M) {
				if (array[nr][nc] == 0)
					melt[r][c]++;
				if (!check[nr][nc] && array[nr][nc] != 0)
					dfs(nr, nc);
			}
		}
	}

	private static void melting() {
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				if (array[i][j] != 0) {
					array[i][j] = (array[i][j] - melt[i][j] < 0) ? 0 : array[i][j] - melt[i][j];
					check[i][j] = false;
					melt[i][j] = 0;
				}
			}
		}
	}
	
	private static class InputReader {
		private InputStream stream;
		private byte[] buf = new byte[1024];
		private int curChar;
		private int numChars;
		private SpaceCharFilter filter;

		public InputReader(InputStream stream) {
			this.stream = stream;
		}

		public int read() {
			if (numChars == -1) {
				throw new InputMismatchException();
			}
			if (curChar >= numChars) {
				curChar = 0;
				try {
					numChars = stream.read(buf);
				} catch (IOException e) {
					throw new InputMismatchException();
				}
				if (numChars <= 0) {
					return -1;
				}
			}
			return buf[curChar++];
		}

		public int readInt() {
			int c = read();
			while (isSpaceChar(c)) {
				c = read();
			}
			int sgn = 1;
			if (c == '-') {
				sgn = -1;
				c = read();
			}
			int res = 0;
			do {
				if (c < '0' || c > '9') {
					throw new InputMismatchException();
				}
				res *= 10;
				res += c - '0';
				c = read();
			} while (!isSpaceChar(c));
			return res * sgn;
		}

		public boolean isSpaceChar(int c) {
			if (filter != null) {
				return filter.isSpaceChar(c);
			}
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}

		public interface SpaceCharFilter {
			public boolean isSpaceChar(int ch);
		}
	}
}

 

1781번: 컵라면

상욱 조교는 동호에게 N개의 문제를 주고서, 각각의 문제를 풀었을 때 컵라면을 몇 개 줄 것인지 제시 하였다. 하지만 동호의 찌를듯한 자신감에 소심한 상욱 조교는 각각의 문제에 대해 데드라

www.acmicpc.net


 

  • 생각

1. 먼저, 2차원 배열에 값들을 넣어준 뒤 2차원 배열 정렬을 deadline으로 한다. 같은 deadline들 중 가장 큰 컵라면의 수를 더 해준다. O(n)의 시간으로 계산할 수 있다. ==>> 문제는 n이 7이고 deadline이 1이 5개, 7이 2개이면 deadline 1중에서 1개를 고르고, 7에서 2개 모두 더해줄 수 있다. (결국, 정확하게 구할 수 없음)

 

2. 먼저, 2차원 배열을 2개 만든다. 1개 배열엔 입력한 값들이 들어가고 1개 배열엔 입력된 배열을 컵라면 수를 내림차순으로 정렬한다. 가장 큰 컵라면 수부터 배열을 채우는데 해당 데드라인에 값이 있으면 해당 데드라인-1에 더 작은 값을 넣는다.   ==>> 시간 초과

 

3. 찾아보니 우선순위 큐를 사용 많이하는 것 같았다.

 

  • 코드
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Comparator;
import java.util.InputMismatchException;
import java.util.PriorityQueue;

public class Main {
	static int N;
	static int[][] array;

	public static void main(String[] args) throws Exception {
		SetData();
		System.out.println(FindMaxValue());
	}
	
	private static void SetData() throws Exception {
		InputReader in = new InputReader(System.in);
		
		N = in.readInt();
		array = new int[N][2];
		
		for(int i = 0; i < N; i++) {
			array[i][0] = in.readInt();
			array[i][1] = in.readInt();
		}
		
		// 2차원 배열 정렬 (deadline 오름차순)
		Arrays.sort(array, new Comparator<int[]>() {
		    @Override
		    public int compare(int[] o1, int[] o2) {
		        return o1[0] - o2[0];
		    }
		});
	}
	
	private static int FindMaxValue() {
        PriorityQueue<Integer> queue = new PriorityQueue<>();
        int sum = 0;
        for (int i = 0; i < N; i++) {
            queue.add(array[i][1]);
            while (!queue.isEmpty() && queue.size() > array[i][0]) 
            	queue.poll();
        }
        while (!queue.isEmpty())
            sum += queue.poll();
		return sum;
	}
	
    // Stream
	private static class InputReader {
		private InputStream stream;
		private byte[] buf = new byte[1024];
		private int curChar;
		private int numChars;
		private SpaceCharFilter filter;

		public InputReader(InputStream stream) {
			this.stream = stream;
		}

		public int read() {
			if (numChars == -1) {
				throw new InputMismatchException();
			}
			if (curChar >= numChars) {
				curChar = 0;
				try {
					numChars = stream.read(buf);
				} catch (IOException e) {
					throw new InputMismatchException();
				}
				if (numChars <= 0) {
					return -1;
				}
			}
			return buf[curChar++];
		}

		public int readInt() {
			int c = read();
			while (isSpaceChar(c)) {
				c = read();
			}
			int sgn = 1;
			if (c == '-') {
				sgn = -1;
				c = read();
			}
			int res = 0;
			do {
				if (c < '0' || c > '9') {
					throw new InputMismatchException();
				}
				res *= 10;
				res += c - '0';
				c = read();
			} while (!isSpaceChar(c));
			return res * sgn;
		}

		public boolean isSpaceChar(int c) {
			if (filter != null) {
				return filter.isSpaceChar(c);
			}
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}

		public interface SpaceCharFilter {
			public boolean isSpaceChar(int ch);
		}
	}
}

 

11000번: 강의실 배정

첫 번째 줄에 N이 주어진다. (1 ≤ N ≤ 200,000) 이후 N개의 줄에 Si, Ti가 주어진다. (1 ≤ Si < Ti ≤ 109)

www.acmicpc.net


 

  • 생각

1. 강의실 시작, 끝나는 시간을 배열에 저장하여서 반복문을 돌린다. 이때 끝나는 시간을 우선순위큐(오름차순 자동 정렬)을 사용해서 맨 앞의 큐보다 해당 시작시간이 더 높은 경우에만 강의실을 배정하면 될 것 같다.

 

2. 위의 방법으로 해보니 틀렸다고 나왔다. 찾아보니 강의실 시작시간 순서대로 배열을 정렬을 해줘야된다...!

 

 

  • 생각대로 했을 때의 생긴 문제점

처음 강의실 시작시간 정렬을 해주지 않아서 삽질 좀 했다. 시작시간 순서대로 정렬을 해준 뒤 강의실 사용 시작 시간과 종료 시간을 통해 강의실 최소개수를 찾았다. 

 

 

  • 코드

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class Main {
	static int N;
	static int[][] room;

	public static void main(String[] args) throws Exception {
		SetData();
		System.out.println(FindMinValue());
	}

	private static void SetData() throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = null;
		N = Integer.parseInt(br.readLine());
		room = new int[N][2];
		
		for(int i = 0; i < N; i++) {
			st = new StringTokenizer(br.readLine());
			room[i][0] = Integer.parseInt(st.nextToken());
			room[i][1] = Integer.parseInt(st.nextToken());
		}
		
		// 2차원 배열 정렬
        Arrays.sort(room, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                int result = o1[0] - o2[0];
                if (result != 0) return result;
                return o1[1] - o2[1];
            }
        });
	}

	private static int FindMinValue() {
		PriorityQueue<Integer> queue = new PriorityQueue<>();

		queue.offer(room[0][1]);
		for(int i=1;i<N;i++) {
			if(room[i][0] < queue.peek()) {
				queue.offer(room[i][1]);
			}else {
				queue.poll();
				queue.offer(room[i][1]);
			}
		}

		return queue.size();
	}
}

 

9663번: N-Queen

N-Queen 문제는 크기가 N × N인 체스판 위에 퀸 N개를 서로 공격할 수 없게 놓는 문제이다. N이 주어졌을 때, 퀸을 놓는 방법의 수를 구하는 프로그램을 작성하시오.

www.acmicpc.net


 

  • 설명

순서대로 체크하기때문에 위, 왼쪽 위, 오른쪽 위만 체크하면서 백트래킹 해주었다.

 

 

  • 코드

 

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {
	static int N;
    static boolean[] flagRow;
    static boolean[] flagDiag1;
    static boolean[] flagDiag2;

	public static void main(String[] args) throws Exception {
		SetData();
		System.out.println(dfs(0));
	}

	private static void SetData() throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		N = Integer.parseInt(br.readLine());
        flagRow = new boolean[N];
        flagDiag1 = new boolean[2 * N - 1];
        flagDiag2 = new boolean[2 * N - 1];
	}
	
    private static int dfs(int depth) {
        if (depth == N) return 1;
        int sum = 0;
        for (int i = 0; i < N; i++) {
            if (!flagRow[i] && !flagDiag1[depth + i] && !flagDiag2[depth - i + N - 1]) {
                flagRow[i] = flagDiag1[depth + i] = flagDiag2[depth - i + N - 1] = true;
                sum += dfs(depth + 1);
                flagRow[i] = flagDiag1[depth + i] = flagDiag2[depth - i + N - 1] = false;

            }
        }
        return sum;
    }
}

d

 

2553번: 마지막 팩토리얼 수

첫째 줄에 N이 주어진다. N은 20,000보다 작거나 같은 자연수 이다.

www.acmicpc.net


 

  • 생각

19996~19999까지 곱하게 된다면 5자리수 * 5자리수 * 5자리수 * 5자리수 이므로 숫자가 조단위가 됩니다. 이 점에 유의하셔야 시간초과를 피할 수 있다.

 

 

  • 코드

 

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {
	static long answer;

	public static void main(String[] args) throws Exception {
		SetData();
		System.out.println(answer%10);
	}

	private static void SetData() throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		long input = Long.parseLong(br.readLine());
		answer =1;
		
		for(int i=1;i<=input;i++) {
			answer*=i;
			answer %= 1000000000;
			while (answer % 10 == 0)
			     answer /= 10;
		}
	}
}

 

2661번: 좋은수열

첫 번째 줄에 1, 2, 3으로만 이루어져 있는 길이가 N인 좋은 수열들 중에서 가장 작은 수를 나타내는 수열만 출력한다. 수열을 이루는 1, 2, 3들 사이에는 빈칸을 두지 않는다.

www.acmicpc.net


 

  • 생각

backtraking 메소드에서 문자열에 1,2,3을 계속 추가시키면서 좋을수열(PossibleNumber 메소드에서 체크)인 수열만 계속 backtraking하다가 수의 길이가 N이면 출력 후 종료(제일 적은 수가 먼저 도착하기 때문)

 

 

  • 코드

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
	static int N;

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		N = Integer.parseInt(br.readLine());

		backtracking("");
	}

	private static void backtracking(String s) {
		if (s.length() == N) {
			System.out.println(s);
			System.exit(0);
		}

		for (int i = 1; i <= 3; i++) {
			if (PossibleNumber(s + i))
				backtracking(s + i);
		}
	}

	private static boolean PossibleNumber(String s) {
		int length = s.length();
		for (int i = 1; i <= length/2; i++) {
			String frontString = s.substring(length-i*2, length-i);
			String backString = s.substring(length-i, length);
			if (frontString.equals(backString))
				return false;
		}

		return true;
	}
}

 

17471번: 게리맨더링

선거구를 [1, 4], [2, 3, 5, 6]으로 나누면 각 선거구의 인구는 9, 8이 된다. 인구 차이는 1이고, 이 값보다 더 작은 값으로 선거구를 나눌 수는 없다.

www.acmicpc.net

 


 

  • 생각

브루트포스 문제로 모든 경우의 수를 다 확인해봐야되는 문제이다.

 

문제를 읽으면서 dfs 방식으로 풀면 된다고 생각이 들었다. (모든 경우의 수를 볼 때 많이 사용함)

 

dfs방식

 

1. N개의 지역을 지역1, 지역2로 할당하면서 돌린다.

2. N개 모두 지역이 할당되면 area1, area2로 인구 수를 구해준다.

3. area1, area2 모두 연결되어 있는지 확인한다.

4. 모두 연결되어 있다면 두 지역의 인구 수 차를 구해 업데이트 시킨다.

 

 

  • 코드
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
	static int N, answer;
	static int[] population, area;
	static boolean[][] connect;
	static boolean[] check;	

	public static void main(String[] args) throws Exception {
		SetData();
		dfs(1);
		if(answer == Integer.MAX_VALUE)
			answer = -1;
		System.out.println(answer);
	}

	private static void SetData() throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = null;
		
		N = Integer.parseInt(br.readLine());
		answer = Integer.MAX_VALUE;
		population = new int[N + 1];
		area = new int[N + 1];
		connect = new boolean[N+1][N+1];
		
		st = new StringTokenizer(br.readLine());
		for(int i = 1; i <= N; i++) {
			population[i] = Integer.parseInt(st.nextToken()); 
		}

		for(int i = 1; i <= N; i++) {
			st = new StringTokenizer(br.readLine());
			int count = Integer.parseInt(st.nextToken());
			for(int j = 0; j < count; j++) {
				int temp = Integer.parseInt(st.nextToken());
				connect[i][temp] = true;
				connect[temp][i] = true;
			}
		}
	}
	
	static void dfs(int count) {
        if(count == N+1) {
        	// 나눈 지역의 인구 수를 구함
            int area1 = 0, area2 = 0;
            for(int i=1; i<=N; i++) {
                if(area[i] == 1)
                    area1 += population[i];
                else
                    area2 += population[i];
            }
            
            // 두 지역으로 나누어 져있는지 체크
            check = new boolean[N+1];
            int result = 0;
            for(int i=1; i<=N; i++) {
                if(!check[i]) {
                    checkArea(i, area[i]);
                    result++;
                }
            }
            
            // 두 지역으로 나누어져 있으면 두 지역 값의 차를 구해서 최소 값 도출
            if(result == 2) {
                if(answer > Math.abs(area1 - area2))
                    answer =  Math.abs(area1 - area2);
            }
            return;
        }
        
        // 지역 1 포함
        area[count] = 1;
        dfs(count+1);
        
        // 지역 2 포함
        area[count] = 2;
        dfs(count+1);
	}
	
    private static void checkArea(int index, int number) {
        check[index] = true;
        for(int i=1; i<=N; i++) {
            if(connect[index][i] && !check[i] && area[i]==number)
                checkArea(i, number);
        }
    }
}

+ Recent posts