두 명의 손님에게 음식을 제공하려고 한다.

두 명의 손님은 식성이 비슷하기 때문에, 최대한 비슷한 맛의 음식을 만들어 내야 한다.

N개의 식재료가 있다.

식재료들을 각각 N / 2개씩 나누어 두 개의 요리를 하려고 한다. (N은 짝수이다.)

이때, 각각의 음식을 A음식, B음식이라고 하자.

비슷한 맛의 음식을 만들기 위해서는 A음식과 B음식의 맛의 차이가 최소가 되도록 재료를 배분해야 한다.

음식의 맛은 음식을 구성하는 식재료들의 조합에 따라 다르게 된다.

 

식재료 i는 식재료 j와 같이 요리하게 되면 궁합이 잘 맞아 시너지 Sij가 발생한다. (1 ≤ i ≤ N, 1 ≤ j ≤ N, i ≠ j)

각 음식의 맛은 음식을 구성하는 식재료들로부터 발생하는 시너지 Sij들의 합이다.

 

식재료 i를 식재료 j와 같이 요리하게 되면 발생하는 시너지 Sij의 정보가 주어지고, 가지고 있는 식재료를 이용해 A음식과 B음식을 만들 때, 두 음식 간의 맛의 차이가 최소가 되는 경우를 찾고 그 최솟값을 정답으로 출력하는 프로그램을 작성하라.

 

[예시]

N = 4인 예를 생각해보자. 시너지 Sij [Table 1]과 같이 주어진다.

(세로축으로 i번째 위치에 있고 가로축으로 j번째 위치에 있는 값이 Sij이다.)

                                        


                                                                      [Table 1]

 

식재료 1과 식재료 2 A음식으로 만들고 식재료 3과 식재료 4 B음식으로 만드는 경우를 생각하자.

 

1) 식재료 1을 식재료 2와 같이 요리했을 때 발생하는 시너지 S12 5이다.

2) 식재료 2를 식재료 1과 같이 요리했을 때 발생하는 시너지 S21 4이다.

3) A음식의 맛은 5 + 4 = 9가 된다.

4) 식재료 3을 식재료 4와 같이 요리했을 때 발생하는 시너지 S34 3이다.

5) 식재료 4를 식재료 3과 같이 요리했을 때 발생하는 시너지 S43 3이다.

6) B음식의 맛은 3 + 3 = 6이 된다.

 

따라서, 두 음식 간의 맛의 차이는 |9 – 6| = 3이 된다.

 

식재료 2와 식재료 4 A음식으로 만들고 식재료 1과 식재료 3 B음식으로 만드는 경우를 생각하자.

 

7) 식재료 2를 식재료 4와 같이 요리했을 때 발생하는 시너지 S24 1이다.

8) 식재료 4를 식재료 2와 같이 요리했을 때 발생하는 시너지 S42 2이다.

9) A음식의 전력은 1 + 2 = 3이 된다.

10) 식재료 1을 식재료 3과 같이 요리했을 때 발생하는 시너지 S13 3이다.

11) 식재료 3과 식재료 1을 같이 요리했을 때 발생하는 시너지 S31 2이다.

12) B음식의 맛은 3 + 2 = 5가 된다.

 

따라서, 두 음식간의 맛의 차이는 |3 – 5| = 2가 된다.

이 경우가 A음식과 B음식 간의 맛의 차이가 최소인 경우이다.

다른 경우에서는 맛의 차이가 2보다 작을 수 없다.

따라서, 본 예의 정답은 2가 된다.

 

 [제약사항]

1. 시간 제한 : 최대 50개 테스트 케이스를 모두 통과하는 데 C / C++ / Java 모두 3

2. 식재료의 수 N 4이상 16이하의 짝수이다. (4 ≤ N ≤ 16)

3. 시너지 Sij 1이상 20,000이하의 정수이다. (1 ≤ Sij ≤ 20,000, i ≠ j)

4. i j가 서로 같은 경우의 Sij값은 정의되지 않는다. 입력에서는 0으로 주어진다.

 

[입력]

입력의 맨 첫 줄에는 총 테스트 케이스의 개수 T가 주어지고,

그 다음 줄부터 T개의 테스트 케이스가 주어진다.

각 테스트 케이스의 첫 번째 줄에는 식재료의 수 N이 주어진다.

다음 N개의 줄에는 N * N개의 시너지 Sij값들이 주어진다. i j가 서로 같은 경우는 0으로 주어진다.

 

[출력]

테스트 케이스 개수만큼 T개의 줄에 각각의 테스트 케이스에 대한 답을 출력한다.

각 줄은 "#t"로 시작하고 공백을 하나 둔 다음 정답을 출력한다. (t  1부터 시작하는 테스트 케이스의 번호이다.)

정답은 두 음식 간의 맛의 차이가 최소가 되도록 A음식과 B음식을 만들었을 때 그 차이 값이다.

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class Solution {
    static int result;
    static int N;
    static int[][] sarr;
 
    static void combi(int toselect, int[] selected, int start) {
        if (toselect == N / 2) {
            // 선택하고 남은 재료
            int[] remain = new int[N / 2];
            for (int i = 0, k = 0, t = 0; i < N; i++) {
                 
                if( k < N/2 &&i == selected[k]) {
                    k++;
                }else {
                    remain[t] = i;
                    t++;
                }
            }
            // 선택한 재료의 시너지 합
            int temp1 = 0;
            for (int i = 0; i < N / 2; i++) {
                for (int j = 0; j < N / 2; j++) {
                    temp1 += sarr[selected[i]][selected[j]];
                }
            }
            // 남은 재료 시너지 합
            int temp2 = 0;
            for (int i = 0; i < N / 2; i++) {
                for (int j = 0; j < N / 2; j++) {
                    temp2 += sarr[remain[i]][remain[j]];
                }
            }
            int dif = Math.abs(temp1 - temp2);
            if (result > dif)
                result = dif;
            return;
        }
        for (int i = start; i < N; i++) {
            selected[toselect] = i;
            combi(toselect + 1, selected, i + 1);
        }
    }
 
    public static void main(String[] args) throws NumberFormatException, IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        StringBuilder sb = new StringBuilder();
        // tesecase 수 입력
        int TC = Integer.parseInt(br.readLine());
        for (int t = 1; t <= TC; t++) {
            // N과 재료의 시너지 값 입력
            N = Integer.parseInt(br.readLine());
            sarr = new int[N][N];
            for (int i = 0; i < N; i++) {
                st = new StringTokenizer(br.readLine(), " ");
                for (int j = 0; j < N; j++) {
                    sarr[i][j] = Integer.parseInt(st.nextToken());
                }
            }
            result = Integer.MAX_VALUE;
            combi(0, new int[N / 2], 0);
 
            sb.append("#" + t + " " + result + "\n");
        }
        System.out.println(sb);
    }
}

스마트폰을 무선 충전 할 때 최적의 BC (Battery Charger)를 선택하는 알고리즘을 개발하고자 한다. [그림 1]과 같이 가로 세로 10*10 영역의 지도가 주어졌을 때, 설치된 BC 정보는 다음과 같다.

  BC 1 BC 2 BC 3
위치 Location (X, Y) (4, 4) (7, 10) (6, 3)
충전 범위 Coverage (C) 1 3 2
성능 Performance (P) 100 40 70

 

               


                                                             [그림 1]

 

 

BC의 충전 범위가 C일 때, BC와 거리가 C 이하이면 BC에 접속할 수 있다. 이때, 두 지점 A(XA, YA), B(XB, YB) 사이의 거리는 다음과 같이 구할 수 있다.

D = |XA – XB| + |YA – YB|

위의 [그림 1]에서 (4,3) (5,4) 지점은 BC 1 BC 3의 충전 범위에 모두 속하기 때문에, 이 위치에서는 두 BC 중 하나를 선택하여 접속할 수 있다.
 

                

       
                                                              [그림 2]

 

[그림 2]와 같이 사용자 A B의 이동 궤적이 주어졌다고 가정하자. T는 초(Second)를 의미한다. 예를 들어 5초에 사용자 A (5, 2) 지점에, 사용자 B (6, 9) 지점에 위치한다.

매초마다 특정 BC의 충전 범위에 안에 들어오면 해당 BC에 접속이 가능하다. 따라서 T=5에 사용자 A BC 3, 사용자 B BC 2에 접속할 수 있다. 이때, 접속한 BC의 성능(P)만큼 배터리를 충전 할 수 있다. 만약 한 BC에 두 명의 사용자가 접속한 경우, 접속한 사용자의 수만큼 충전 양을 균등하게 분배한다.

BC의 정보와 사용자의 이동 궤적이 주어졌을 때, 모든 사용자가 충전한 양의 합의 최댓값을 구하는 프로그램을 작성하라.
 

[그림 2]에서 T=11일 때, 사용자 A BC 1 3 둘 중 하나에 접속이 가능하다. 같은 시간에 사용자 B BC 1에 접속할 수 밖에 없다. 따라서 사용자 A가 같은 BC 1에 접속한다면 충전되는 양를 반씩 나눠 갖게 되어 비효율적이다. 따라서 사용자 A BC 3에 접속하는 것이 더 이득이다.
 

T=11 사용자 A 사용자 B 충전량 합
접속한 BC
(충전량)
BC 1 (50) BC 1 (50) 50 + 50 = 100
BC 3 (70) BC 1 (100) 70 + 100 = 170

 
 

위 예제에서 매 초마다 충전한 양은 다음과 같다. 따라서 총 충전한 양의 총합은 720 + 480 = 1200 이다.
 

시간(T) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Sum
사용자A 0 0 0 0 0 70 70 70 70 70 70 70 0 70 0 0 40 40 40 0 40 720
사용자B 40 40 40 40 40 40 40 0 0 0 0 100 0 100 0 0 0 0 0 0 0 480

 

[제약사항]

1. 지도의 가로, 세로 크기는 10이다.
2. 사용자는 총 2명이며, 사용자A는 지도의 (1, 1) 지점에서, 사용자B는 지도의 (10, 10) 지점에서 출발한다
.
3. 총 이동 시간 M 20이상 100이하의 정수이다. (20 ≤ M ≤ 100
)
4. BC의 개수 A 1이상 8이하의 정수이다. (1 ≤ A ≤ 8
)
5. BC의 충전 범위 C 1이상 4이하의 정수이다. (1 ≤ C ≤ 4
)
6. BC의 성능 P 10이상 500이하의 짝수이다. (10 ≤ P ≤ 500
)
7. 사용자의 초기 위치(0)부터 충전을 할 수 있다.

8. 같은 위치에 2개 이상의 BC가 설치된 경우는 없다. 그러나 사용자A, B가 동시에 같은 위치로 이동할 수는 있다. 사용자가 지도 밖으로 이동하는 경우는 없다.
 

[입력]

입력의 맨 첫 줄에는 총 테스트 케이스의 개수 T가 주어지고, 그 다음 줄부터 T개의 테스트 케이스가 주어진다.
테스트 케이스의 첫 번째 줄에는 총 이동 시간(M), BC의 개수(A)가 주어진다
.
그 다음 2개의 줄에는 각각 사용자 A B의 이동 정보가 주어진다
.
한 사용자의 이동 정보는 M개의 숫자로 구성되며, 각각의 숫자는 다음과 같이 매초마다 이동 방향을 의미한다.

 

숫자 0 1 2 3 4
이동 방향 이동하지 않음 상 (UP) 우 (RIGHT) 하 (DOWN) 좌 (LEFT)


그 다음 줄에는 A개의 줄에 걸쳐 BC의 정보가 주어진다.
하나의 BC 정보는 좌표(X, Y), 충전 범위(C), 처리량(P)로 구성된다.

 

[출력]

출력은 "#t"를 찍고 한 칸 띄운 다음 정답을 출력한다. (t는 테스트 케이스의 번호를 의미하며 1부터 시작한다.)
정답은 모든 사용자의 충전량 합의 최대값을 출력한다.

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
 
public class Solution {
    // 이동 좌표 찾는 함수
    static int[] go(int dir, int[] loc) {
        int[] location = new int[2];
        int[][] delta = { { 0, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } };
        location[0] = loc[0] + delta[dir][0];
        location[1] = loc[1] + delta[dir][1];
        return location;
    }
 
    public static void main(String[] args) throws NumberFormatException, IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        StringBuilder sb = new StringBuilder();
        int TC = Integer.parseInt(br.readLine());
        for (int t = 1; t <= TC; t++) {
            sb.append("#" + t + " ");
            
            // 결과
            int result = 0;
 
            // a, b의 현재 위치
            int[] a_loc = { 1, 1 };
            int[] b_loc = { 10, 10 };
            
            // 이동시간, BC의 개수
            st = new StringTokenizer(br.readLine(), " ");
            int M = Integer.parseInt(st.nextToken());
            int A = Integer.parseInt(st.nextToken());
            int[] a = new int[M];
            int[] b = new int[M];
            st = new StringTokenizer(br.readLine(), " ");
            for (int i = 0; i < M; i++) {
                a[i] = Integer.parseInt(st.nextToken());
            }
            st = new StringTokenizer(br.readLine(), " ");
            for (int i = 0; i < M; i++) {
                b[i] = Integer.parseInt(st.nextToken());
            }
 
            // BC의 정보 [0],[1] = (x,y), [2] = C, [3] = P
            int[][] bc = new int[A][4];
            for (int i = 0; i < A; i++) {
                st = new StringTokenizer(br.readLine(), " ");
                for (int j = 0; j < 4; j++) {
                    bc[i][j] = Integer.parseInt(st.nextToken());
                }
            }
            // 이동시간 M동안
            for (int i = 0; i <= M; i++) {
                
                // t(i) 시간에 사용자의 위치에서 접속할 수 있는 BC의 리스트
                List<Integer> list_a = new ArrayList<Integer>();
                List<Integer> list_b = new ArrayList<Integer>();
               
               // A개의 BC에 대해
                for (int j = 0; j < A; j++) {
                    int Dist_a = Math.abs(bc[j][0] - a_loc[0]) + Math.abs(bc[j][1] - a_loc[1]);
                    int Dist_b = Math.abs(bc[j][0] - b_loc[0]) + Math.abs(bc[j][1] - b_loc[1]);
                    
                    //접속가능한 거리에 있으면 list에 저장 
                    if (Dist_a <= bc[j][2]) {
                        list_a.add(j);
                    }
                    if (Dist_b <= bc[j][2]) {
                        list_b.add(j);
                    }
                }
                // 사용자가 접근할 수 있는 BC조합
                int atemp = 0;
                int btemp = 0;
                int tempsum = 0;
                //a가 접근가능한 BC가 존재한 경우
                if (list_a.size() != 0) {
                    for (int a_index : list_a) {
                        atemp = bc[a_index][3];
                        //b가 접근 가능한 BC가 없다면
                        if (list_b.size() == 0) {
                            if (tempsum < atemp + btemp) {
                                tempsum = atemp + btemp;
                            }
                        }
                        //b가 접근 가능한 BC가 있다면
                        else {
                            for (int b_index : list_b) {
                                atemp = bc[a_index][3];
                                btemp = bc[b_index][3];
                                // 사용자들이 선택한 bc가 같으면 1/2
                                if (a_index == b_index) {
                                    atemp /= 2;
                                    btemp /= 2;
                                }
                                if (tempsum < atemp + btemp) {
                                    tempsum = atemp + btemp;
                                }
                            }
                        }
                    }
                    //최대값  갱신
                    if (result < result + tempsum)
                        result += tempsum;
                }
                //a가 접근가능한 BC가 존재하지 않는 경우
                else {
                    atemp = 0;
                    btemp = 0;
                    tempsum = 0;
                    //list_b만 check
                    for (int b_index : list_b) {
                        btemp = bc[b_index][3];
                        if (tempsum < atemp + btemp)
                            tempsum = atemp + btemp;
                    }
                    //최대값 갱신
                    if (result < result + tempsum)
                        result += tempsum;
                }
                // ab 위치 이동
                if (i < M) {
                    a_loc = go(a[i], a_loc);
                    b_loc = go(b[i], b_loc);
                }
            }
            sb.append(result + "\n");
        }
        System.out.println(sb);
    }
}

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

 

2477번: 참외밭

첫 번째 줄에 1m2의 넓이에 자라는 참외의 개수를 나타내는 양의 정수 K (1 ≤ K ≤ 20)가 주어진다. 참외밭을 나타내는 육각형의 임의의 한 꼭짓점에서 출발하여 반시계방향으로 둘레를 돌면서 지

www.acmicpc.net

 

문제

시골에 있는 태양이의 삼촌 댁에는 커다란 참외밭이 있다. 문득 태양이는 이 밭에서 자라는 참외가 도대체 몇 개나 되는지 궁금해졌다. 어떻게 알아낼 수 있는지 골똘히 생각하다가 드디어 좋은 아이디어가 떠올랐다. 유레카! 1m2의 넓이에 자라는 참외 개수를 헤아린 다음, 참외밭의 넓이를 구하면 비례식을 이용하여 참외의 총개수를 구할 수 있다.

1m2의 넓이에 자라는 참외의 개수는 헤아렸고, 이제 참외밭의 넓이만 구하면 된다. 참외밭은 ㄱ-자 모양이거나 ㄱ-자를 90도, 180도, 270도 회전한 모양(┏, ┗, ┛ 모양)의 육각형이다. 다행히도 밭의 경계(육각형의 변)는 모두 동서 방향이거나 남북 방향이었다. 밭의 한 모퉁이에서 출발하여 밭의 둘레를 돌면서 밭경계 길이를 모두 측정하였다.

예를 들어 참외밭이 위 그림과 같은 모양이라고 하자. 그림에서 오른쪽은 동쪽, 왼쪽은 서쪽, 아래쪽은 남쪽, 위쪽은 북쪽이다. 이 그림의 왼쪽위 꼭짓점에서 출발하여, 반시계방향으로 남쪽으로 30m, 동쪽으로 60m, 남쪽으로 20m, 동쪽으로 100m, 북쪽으로 50m, 서쪽으로 160m 이동하면 다시 출발점으로 되돌아가게 된다.

위 그림의 참외밭  면적은 6800m2이다. 만약 1m2의 넓이에 자라는 참외의 개수가 7이라면, 이 밭에서 자라는 참외의 개수는 47600으로 계산된다.

1m2의 넓이에 자라는 참외의 개수와, 참외밭을 이루는 육각형의 임의의 한 꼭짓점에서 출발하여 반시계방향으로 둘레를 돌면서 지나는 변의 방향과 길이가 순서대로 주어진다. 이 참외밭에서 자라는 참외의 수를 구하는 프로그램을 작성하시오.

입력

첫 번째 줄에 1m2의 넓이에 자라는 참외의 개수를 나타내는 양의 정수 K (1 ≤ K ≤ 20)가 주어진다. 참외밭을 나타내는 육각형의 임의의 한 꼭짓점에서 출발하여 반시계방향으로 둘레를 돌면서 지나는 변의 방향과 길이 (1 이상 500 이하의 정수) 가 둘째 줄부터 일곱 번째 줄까지 한 줄에 하나씩 순서대로 주어진다. 변의 방향에서 동쪽은 1, 서쪽은 2, 남쪽은 3, 북쪽은 4로 나타낸다.

출력

첫째 줄에 입력으로 주어진 밭에서 자라는 참외의 수를 출력한다.

 

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

public class BJ_02477 {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;
		int K = Integer.parseInt(br.readLine());
		Queue<int[]> q = new LinkedList<int[]>();
		int[] cnt = new int[5];
		for (int i = 0; i < 6; i++) {
			st = new StringTokenizer(br.readLine(), " ");
			int[] temp = new int[2];
			temp[0] = Integer.parseInt(st.nextToken());
			temp[1] = Integer.parseInt(st.nextToken());
			q.add(temp);
			// 방향 개수 세기
			cnt[temp[0]]++;
		}

		// 전체 넓이 계산
		int area = 1;
		for (int[] temp : q) {
			// 방향이 오직 한개이면 가로 혹은 세로 길이
			if (cnt[temp[0]] == 1) {
				area *= temp[1];
			}
		}

		//빼야할 넓이 계산		
		//1번째, 2 번째 원소 가져오기
		int[] temp1 = q.poll();
		q.add(temp1);
		int[] temp2 = q.poll();
		q.add(temp2);
		
		int withdraw = 1;
		int t = 0;
		while (true) {
			//종료 조건
			if (t == 2) break;
			//다음 원소 가져오기
			int[] temp3 = q.poll();
			q.add(temp3);
			//i번째 원소와 i+2번째 원소가 같으면
			if (temp1[0] == temp3[0]) {
				//i+1번째 원소가 빼야할 넓이의 가로 또는 세로
				withdraw *= temp2[1];
				t++;
			}
			//다음 비교를 위해 원소 밀어주기
			//i -> i+1
			//i+1-> i+2
			temp1 = temp2;
			temp2= temp3;
		}
		//결과 출력
		System.out.println((area - withdraw) * K);
	}
}

 

 

다음과 같은 참외밭의 전체 사각형에서 오목한 부분의 사각형의 넓이를 빼주는 방식으로 풀이하였습니다.

 

방향의 개수가 1개로 유일하면 해당 이동방향의 길이가 전체 사각형의 가로 혹은 세로 길이로 전체 사각형의 넓이를 구할 수 있습니다.

 

같은 방향 사이에 끼인 경우, 끼어있는 이동 길이가 빼야할 사각형의 가로 혹은 세로 길이가 되어 빼야할 사각형의 넓이를 구할 수 있습니다.

 

하지만 이동은 참외밭의 어느 꼭짓점에서든 시작할 수 있으므로, 끼인 경우를 찾기 위해서 원형큐로 구현해 주었습니다.

 

다음과 같이 원형큐를 돌면서 끼인 경우를 2개를 찾게 되면 원형 큐 탐색을 끝내줍니다.

 

(전체 넓이-오목한 부분의 넓이)*K(1m^2의 넓이에 자라는 참외의 개수)를 계산해 출력해주었습니다.

'문제해결 > 백준' 카테고리의 다른 글

백준 1987번-알파벳(JAVA)  (0) 2021.08.19
백준 1992번-쿼드트리(JAVA)  (0) 2021.08.18
백준 2491번-수열(JAVA)  (0) 2021.08.18
백준 1074번-Z(JAVA)  (0) 2021.08.17
백준 2839번-설탕 배달(JAVA)  (0) 2021.08.17

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

 

2491번: 수열

0에서부터 9까지의 숫자로 이루어진 N개의 숫자가 나열된 수열이 있다. 그 수열 안에서 연속해서 커지거나(같은 것 포함), 혹은 연속해서 작아지는(같은 것 포함) 수열 중 가장 길이가 긴 것을 찾

www.acmicpc.net

 

문제

0에서부터 9까지의 숫자로 이루어진 N개의 숫자가 나열된 수열이 있다. 그 수열 안에서 연속해서 커지거나(같은 것 포함), 혹은 연속해서 작아지는(같은 것 포함) 수열 중 가장 길이가 긴 것을 찾아내어 그 길이를 출력하는 프로그램을 작성하라. 

예를 들어 수열 1, 2, 2, 4, 4, 5, 7, 7, 2 의 경우에는 1 ≤ 2 ≤ 2 ≤ 4 ≤ 4 ≤ 5 ≤ 7 ≤ 7 이 가장 긴 구간이 되므로 그 길이 8을 출력한다. 수열 4, 1, 3, 3, 2, 2, 9, 2, 3 의 경우에는 3 ≥ 3 ≥ 2 ≥ 2 가 가장 긴 구간이 되므로 그 길이 4를 출력한다. 또 1, 5, 3, 6, 4, 7, 1, 3, 2, 9, 5 의 경우에는 연속해서 커지거나 작아지는 수열의 길이가 3 이상인 경우가 없으므로 2를 출력하여야 한다.

입력

첫째 줄에는 수열의 길이 N이 주어지고, 둘째 줄에는 N개의 숫자가 빈칸을 사이에 두고 주어진다. N은 1 이상 100,000 이하의 정수이다.

출력

첫째 줄에 가장 긴 길이를 출력한다.

 

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

public class BJ_02491 {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;
		int N = Integer.parseInt(br.readLine());
		st = new StringTokenizer(br.readLine(), " ");
		
		//수열의 개수와, 같은 수의 개수, 수열의 최대길이는 수가 하나만 있어도 1이므로 1로 초기화
		////수열의 개수
		int cnt = 1;
		////같은 수의 개수
		int same = 1;
		//수열의 최대 길이 result
		int result = 1;
		
		
		//수열의 방향(<(=0) 또는 >(=1))
		//초기에는 어느 방향도 아니므로 -1로 초기화
		int flag = -1;
		
		//temp1 = n번째 원소 
		int temp1 = Integer.parseInt(st.nextToken());
		for (int n = 1; n < N; n++) {
			//temp2 n+1번째 원소
			int temp2 = Integer.parseInt(st.nextToken());
			//n번째 원소와 n+1번째 원소가 같을 경우
			if (temp1 == temp2) {
				//같은수의 개수++
				same++;
				//수열의 개수+1
				cnt += 1;
			} 
			//n번째 원소 < n+1번째 원소 일 경우 (flag = 0)
			else if (temp1 < temp2) {
				//수열의 방향이 바뀐 경우
				if (flag == 1) {
					//새로운 수열이 시작되므로 초기값인 1에 same을 더해줌 (13번 주석 참조)
					//수열의 개수 = 초기값+현재 원소 이전의 같은 수의 개수
					cnt = 1 + same;
				} 
				//수열의 방향이 바뀌지 않은 경우 수열의 개수++
				else
					cnt++;
				//temp1 != temp2 이므로 같은 수의 개수는 1로 되돌려줌.
				same = 1;
				//수열의 방향 갱신
				flag = 0;
			}
			//n번째 원소 > n+1번째 원소 일 경우 (flag = 1)
			//이하 else문의 설명은 위의 line 39~53의 설명과 동일
			else {
				if (flag == 0) {
					cnt = 1 + same;
				} else
					cnt++;
				same = 1;
				flag = 1;
			}
			//수열의 최대 길이 갱신
			if (result < cnt)
				result = cnt;
			//temp1에 temp2를 대입해 다음 비교 진행
			temp1 = temp2;
		}
		//결과 출력
		System.out.println(result);
	}
}

 

같은 수가 나오면 같은 수의 개수를 세어 수열의 방향이 바뀔때에 초기값에 더해주는 방식으로 풀이하였습니다.

'문제해결 > 백준' 카테고리의 다른 글

백준 1992번-쿼드트리(JAVA)  (0) 2021.08.18
백준 2477번-참외밭(JAVA)  (0) 2021.08.18
백준 1074번-Z(JAVA)  (0) 2021.08.17
백준 2839번-설탕 배달(JAVA)  (0) 2021.08.17
백준 2628번-종이자르기(JAVA)  (0) 2021.08.16

http://jungol.co.kr/bbs/board.php?bo_table=pbank&wr_id=1101&sca=30 

 

JUNGOL

 

www.jungol.co.kr

 

문제

N개의 화학 물질 C1, C2, …, Cn이 있다. 

이들 각각은 보관되어야 할 온도가 각기 다른데, 각 Ci마다 최저 보관 온도 xi와 최고 보관 온도 yi가 정해져 있다. 

즉 Ci는 온도 xi이상, yi이하의 온도에서 보관되어야만 안전하다.

 

이 화학 물질들을 모두 보관하기 위해서는 여러 대의 냉장고가 필요한데 가능하면 적은 수의 냉장고를 사용하고 싶다. 

이를 해결하는 프로그램을 작성하시오.

 

입력형식

첫줄에 화학물질의 수 N이 입력된다. N의 범위는 1이상 100 이하이다. 

두 번째 줄부터 N+1줄까지 최저보관온도와 최고보관온도가 입력된다. 

보관온도는 -270° ~ 10000°이며, 각 냉장고는 임의의 정해진 온도를 일정하게 유지할 수 있고, 냉장고는 아주 크다고 가정한다.

 

출력형식

첫줄에 최소로 필요한 냉장고의 대수를 출력한다.

 

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

public class refrigerator {
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;
		int N = Integer.parseInt(br.readLine());
		int result = 1;
		int max_x = Integer.MIN_VALUE;
		int min_y = Integer.MAX_VALUE;
		int[][] arr = new int[N][2];
		for (int t = 0; t < N; t++) {
			String str = br.readLine();
			st = new StringTokenizer(str, " ");
			arr[t][0] = Integer.parseInt(st.nextToken());
			arr[t][1] = Integer.parseInt(st.nextToken());
		}
		Arrays.sort(arr, new  Comparator<int[]>() {
			@Override
			public int compare(int[] o1, int[] o2) {
				if(o1[0]==o2[0]) {
					return o1[1]-o2[1];
				}else {
					return o1[0]-o2[0];
				}
			}
		});
		for (int[] temp : arr) {
			if (max_x > temp[1] || min_y < temp[0]) {
				result++;
				max_x = temp[0];
				min_y = temp[1];
				continue;
			}
			max_x = max_x < temp[0] ? temp[0] : max_x;
			min_y = min_y > temp[1] ? temp[1] : min_y;
		}
		System.out.println(result);
	}
}

 

이중배열 arr를 오름차순 정렬한 뒤

Arrays.sort(arr, new  Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if(o1[0]==o2[0]) {
return o1[1]-o2[1];
}else {
return o1[0]-o2[0];
}
}
});

 

현재까지의 수용 가능 범위를 벗어나면 냉장고의 수를 +1 해주고 수용 범위를 변경해 주고,

if (max_x > temp[1] || min_y < temp[0]) {
result++;
max_x = temp[0];
min_y = temp[1];
continue;
}

 

수용 범위를 벗어나지 않으면 수용 범위와 xi, yi를 비교해 수용 범위를 갱신해주는 풀이입니다.

max_x = max_x < temp[0] ? temp[0] : max_x;
min_y = min_y > temp[1] ? temp[1] : min_y;

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

 

1074번: Z

한수는 크기가 2N × 2N인 2차원 배열을 Z모양으로 탐색하려고 한다. 예를 들어, 2×2배열을 왼쪽 위칸, 오른쪽 위칸, 왼쪽 아래칸, 오른쪽 아래칸 순서대로 방문하면 Z모양이다. 만약, N > 1이 라서

www.acmicpc.net

 

문제

한수는 크기가 2N × 2N인 2차원 배열을 Z모양으로 탐색하려고 한다. 예를 들어, 2×2배열을 왼쪽 위칸, 오른쪽 위칸, 왼쪽 아래칸, 오른쪽 아래칸 순서대로 방문하면 Z모양이다.

만약, N > 1이 라서 왼쪽 위에 있는 칸이 하나가 아니라면, 배열을 크기가 2N-1 × 2N-1로 4등분 한 후에 재귀적으로 순서대로 방문한다.

다음 예는 22 × 22 크기의 배열을 방문한 순서이다.

N이 주어졌을 때, r행 c열을 몇 번째로 방문하는지 출력하는 프로그램을 작성하시오.

다음은 N=3일 때의 예이다.

입력

첫째 줄에 정수 N, r, c가 주어진다.

출력

r행 c열을 몇 번째로 방문했는지 출력한다.

 

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

public class z {
	static int p = 0;
	static int r;
	static int c;

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine(), " ");
		int N = Integer.parseInt(st.nextToken());
		r = Integer.parseInt(st.nextToken());
		c = Integer.parseInt(st.nextToken());
		visit(0, 0, N);
	}

	static void visit(int row, int col, int cnt) {
		if (row == r && col == c) {
			System.out.println(p);
			return;
		}
		int t = (int) Math.pow(2, cnt - 1);
		if (r < row + t && c < col + t) {
			visit(row, col, cnt - 1);
			return;
		}
		if (r < row + t && c >= col + t) {
			p += t * t * 1;
			visit(row, col + t, cnt - 1);
			return;
		}
		if (r >= row + t && c < col + t) {
			p += t * t * 2;
			visit(row + t, col, cnt - 1);
			return;
		}
		if (r >= row + t && c >= col + t) {
			p += t * t * 3;
			visit(row + t, col + t, cnt - 1);
			return;
		}
	}
}

 

r과 c의 값에 따라 4분면을 지정해 탐색하도록 풀이해 주었습니다.

'문제해결 > 백준' 카테고리의 다른 글

백준 2477번-참외밭(JAVA)  (0) 2021.08.18
백준 2491번-수열(JAVA)  (0) 2021.08.18
백준 2839번-설탕 배달(JAVA)  (0) 2021.08.17
백준 2628번-종이자르기(JAVA)  (0) 2021.08.16
백준 15686번-치킨 배달(JAVA)  (0) 2021.08.13

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

 

2839번: 설탕 배달

상근이는 요즘 설탕공장에서 설탕을 배달하고 있다. 상근이는 지금 사탕가게에 설탕을 정확하게 N킬로그램을 배달해야 한다. 설탕공장에서 만드는 설탕은 봉지에 담겨져 있다. 봉지는 3킬로그

www.acmicpc.net

 

문제

상근이는 요즘 설탕공장에서 설탕을 배달하고 있다. 상근이는 지금 사탕가게에 설탕을 정확하게 N킬로그램을 배달해야 한다. 설탕공장에서 만드는 설탕은 봉지에 담겨져 있다. 봉지는 3킬로그램 봉지와 5킬로그램 봉지가 있다.

상근이는 귀찮기 때문에, 최대한 적은 봉지를 들고 가려고 한다. 예를 들어, 18킬로그램 설탕을 배달해야 할 때, 3킬로그램 봉지 6개를 가져가도 되지만, 5킬로그램 3개와 3킬로그램 1개를 배달하면, 더 적은 개수의 봉지를 배달할 수 있다.

상근이가 설탕을 정확하게 N킬로그램 배달해야 할 때, 봉지 몇 개를 가져가면 되는지 그 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N이 주어진다. (3 ≤ N ≤ 5000)

출력

상근이가 배달하는 봉지의 최소 개수를 출력한다. 만약, 정확하게 N킬로그램을 만들 수 없다면 -1을 출력한다.

 

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

public class sugar {
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int N = Integer.parseInt(br.readLine());
		int result = Integer.MAX_VALUE;
		for(int a = 0; a <= N/5; a++) {
			for(int b = 0; b <= N/3; b++) {
				if(5*a +3*b == N) {
					 result = result>a+b?a+b:result;
				}
			}
		}	
		result = result == Integer.MAX_VALUE? -1:result;
		System.out.println(result);
	}
}

'문제해결 > 백준' 카테고리의 다른 글

백준 2491번-수열(JAVA)  (0) 2021.08.18
백준 1074번-Z(JAVA)  (0) 2021.08.17
백준 2628번-종이자르기(JAVA)  (0) 2021.08.16
백준 15686번-치킨 배달(JAVA)  (0) 2021.08.13
백준 17135번-캐슬 디펜스(JAVA)  (0) 2021.08.13

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

 

2628번: 종이자르기

첫줄에는 종이의 가로와 세로의 길이가 차례로 자연수로 주어진다. 가로와 세로의 길이는 최대 100㎝이다. 둘째 줄에는 칼로 잘라야하는 점선의 개수가 주어진다. 셋째 줄부터 마지막 줄까지 한

www.acmicpc.net

 

문제

아래 <그림 1>과 같이 직사각형 모양의 종이가 있다. 이 종이는 가로방향과 세로 방향으로 1㎝마다 점선이 그어져 있다. 가로 점선은 위에서 아래로 1번부터 차례로 번호가 붙어 있고, 세로 점선은 왼쪽에서 오른쪽으로 번호가 붙어 있다.

<그림 1>

점선을 따라 이 종이를 칼로 자르려고 한다. 가로 점선을 따라 자르는 경우는 종이의 왼쪽 끝에서 오른쪽 끝까지, 세로 점선인 경우는 위쪽 끝에서 아래쪽 끝까지 한 번에 자른다. 예를 들어, <그림 1>의 가로 길이 10㎝이고 세로 길이 8㎝인 종이를 3번 가로 점선, 4번 세로 점선, 그리고 2번 가로 점선을 따라 자르면 <그림 2>와 같이 여러 개의 종이 조각으로 나뉘게 된다. 이때 가장 큰 종이 조각의 넓이는 30㎠이다.

<그림 2>

입력으로 종이의 가로 세로 길이, 그리고 잘라야할 점선들이 주어질 때, 가장 큰 종이 조각의 넓이가 몇 ㎠인지를 구하는 프로그램을 작성하시오.

입력

첫줄에는 종이의 가로와 세로의 길이가 차례로 자연수로 주어진다. 가로와 세로의 길이는 최대 100㎝이다. 둘째 줄에는 칼로 잘라야하는 점선의 개수가 주어진다. 셋째 줄부터 마지막 줄까지 한 줄에 점선이 하나씩 아래와 같은 방법으로 입력된다. 가로로 자르는 점선은 0과 점선 번호가 차례로 주어지고, 세로로 자르는 점선은 1과 점선 번호가 주어진다. 입력되는 두 숫자 사이에는 빈 칸이 하나씩 있다.

출력

첫째 줄에 가장 큰 종이 조각의 넓이를 출력한다. 단, 넓이의 단위는 출력하지 않는다.

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class area {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String str = br.readLine();
		StringTokenizer st = new StringTokenizer(str, " ");
		
		int N = Integer.parseInt(st.nextToken());
		int M = Integer.parseInt(st.nextToken());
		
		List<Integer> list_x = new ArrayList<Integer>();
		List<Integer> list_y = new ArrayList<Integer>();
		list_x.add(0);
		list_x.add(M);
		list_y.add(0);
		list_y.add(N);
		
		int TC = Integer.parseInt(br.readLine());
		for (int t = 1; t <= TC; t++) {
			str = br.readLine();
			st = new StringTokenizer(str, " ");
			int dir = Integer.parseInt(st.nextToken());
			int num = Integer.parseInt(st.nextToken());
			switch (dir) {
			case 0:
				list_x.add(num);
				break;
			case 1:
				list_y.add(num);
				break;
			}
		}
		list_x.sort(null);
		list_y.sort(null);

		int max_x = Integer.MIN_VALUE;
		for (int i = 0; i < list_x.size() - 1; i++) {
			int temp = list_x.get(i+1) - list_x.get(i);
			if (max_x < temp)
				max_x = temp;
		}
		int max_y = Integer.MIN_VALUE;
		for (int i = 0; i < list_y.size()-1; i++) {
			int temp = list_y.get(i+1) - list_y.get(i);
			if (max_y < temp)
				max_y = temp;
		}
		System.out.println(max_x*max_y);
	}
}

가로로 자르는 list_x 와 세로로 자르는 list_y에 각각 0 과 M, 0 과 N을 넣고

List<Integer> list_x = new ArrayList<Integer>();
List<Integer> list_y = new ArrayList<Integer>();
list_x.add(0);
list_x.add(M);
list_y.add(0);
list_y.add(N);

 

자르는 선들을 입력받아 정렬합니다.

int TC = Integer.parseInt(br.readLine());
for (int t = 1; t <= TC; t++) {
str = br.readLine();
st = new StringTokenizer(str, " ");
int dir = Integer.parseInt(st.nextToken());
int num = Integer.parseInt(st.nextToken());
switch (dir) {
case 0:
list_x.add(num);
break;
case 1:
list_y.add(num);
break;
}
}
list_x.sort(null);
list_y.sort(null);

 

점선과 점선 사이의 길이를 temp에 저장해 종이를 점선에 따라 잘랐을 경우 가장 긴 길이인  max_x와 msx_y를 구해

int max_x = Integer.MIN_VALUE;
for (int i = 0; i < list_x.size() - 1; i++) {
int temp = list_x.get(i+1) - list_x.get(i);
if (max_x < temp)
max_x = temp;
}
int max_y = Integer.MIN_VALUE;
for (int i = 0; i < list_y.size()-1; i++) {
int temp = list_y.get(i+1) - list_y.get(i);
if (max_y < temp)
max_y = temp;
}

 

이를 곱해준 값이 문제에서 원하는 출력값이 되도록 풀이해 주었습니다.

System.out.println(max_x*max_y);

'문제해결 > 백준' 카테고리의 다른 글

백준 1074번-Z(JAVA)  (0) 2021.08.17
백준 2839번-설탕 배달(JAVA)  (0) 2021.08.17
백준 15686번-치킨 배달(JAVA)  (0) 2021.08.13
백준 17135번-캐슬 디펜스(JAVA)  (0) 2021.08.13
백준 2564번-경비원(JAVA)  (0) 2021.08.13

+ Recent posts