[백준] 연속합 (java) Math

2020-02-25

연속합 (백준 > Math)

문제 링크

문제설명

n개의 정수로 이루어진 임의의 수열이 주어진다. 우리는 이 중 연속된 몇 개의 수를 선택해서 구할 수 있는 합 중 가장 큰 합을 구하려고 한다. 단, 수는 한 개 이상 선택해야 한다.

예를 들어서 10, -4, 3, 1, 5, 6, -35, 12, 21, -1 이라는 수열이 주어졌다고 하자. 여기서 정답은 12+21인 33이 정답이 된다.

입력

첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.

출력

첫째 줄에 답을 출력한다.

예제 입력 1 복사

10
10 -4 3 1 5 6 -35 12 21 -1

예제 출력 1 복사

33


풀이

package Math;

import java.util.*;

//30min
public class beak_연속합 {
	
	//당연하게도 10만씩 for돌리면 100억이라서 에러나는 문제..
    public static void main(String args[]){
        Scanner sc = new Scanner(System.in);
        
        int n = sc.nextInt();
        int arr[] = new int[n];
        int dp[] = new int[n];
        
        for(int i=0; i<n; i++){
            arr[i] = sc.nextInt();
        }
        
        dp[0] = arr[0];
        
        for(int i=1;i<n;i++){//내 전과 더한게 크면 넣고 or 내가 더크면 나부터 다시 시작!
            dp[i] = Math.max(arr[i], dp[i-1] + arr[i]);
        }
        
        int max = dp[0]; // max값을 당연히 0으로 초기화하면 값이 틀릴 수 도 있다는 점!!!
        for(int i=1;i<n;i++)
            max = Math.max(max, dp[i]);
        
        
        System.out.println(max);
    }
}

후기 (30min)

10만개이기 때문에 당연히 for 두번 돌리면 100억이라 처음에는 초과가 떴다.

따라서 dp로 풀어야하는 문제였고, 배열에 내 전과 더한 것을 계속 더해주고, 그거보다 내가 더 크면 다시 나부터 시작한다는 조건을 걸어주면 쉽게 풀렸다


tip

  1. dp는 정말 풀어도 풀어도.. 너무 문제 낸 사람들 천재같아


Read More

[백준] 로프 (java) Greedy

2020-02-25

로프 (백준> Greedy)

문제 링크

문제설명

N(1≤N≤100,000)개의 로프가 있다. 이 로프를 이용하여 이런 저런 물체를 들어올릴 수 있다. 각각의 로프는 그 굵기나 길이가 다르기 때문에 들 수 있는 물체의 중량이 서로 다를 수도 있다.

하지만 여러 개의 로프를 병렬로 연결하면 각각의 로프에 걸리는 중량을 나눌 수 있다. k개의 로프를 사용하여 중량이 w인 물체를 들어올릴 때, 각각의 로프에는 모두 고르게 w/k 만큼의 중량이 걸리게 된다.

각 로프들에 대한 정보가 주어졌을 때, 이 로프들을 이용하여 들어올릴 수 있는 물체의 최대 중량을 구해내는 프로그램을 작성하시오. 모든 로프를 사용해야 할 필요는 없으며, 임의로 몇 개의 로프를 골라서 사용해도 된다. 단, 각각의 로프는 한 개씩만 존재한다.

입력

첫째 줄에 정수 N이 주어진다. 다음 N개의 줄에는 각 로프가 버틸 수 있는 최대 중량이 주어진다. 이 값은 10,000을 넘지 않는 정수이다.

출력

첫째 줄에 답을 출력한다.

예제 입력 1 복사

2
10
15

예제 출력 1 복사

20


풀이

package Greedy;

import java.util.*;

//30min
public class beak_로프 {
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		int n = sc.nextInt();
		
		int arr[] = new int[n];
		
		for(int i=0;i<n;i++) {
			arr[i] = sc.nextInt();
		}
		
		Arrays.sort(arr);
		
		int size = 1;
		int max = 0;
		
		//제일 작은 숫자 * size가 답이 아니고 중량으로 칠 수 있는거 * size가 제일 큰게 답이라는것!
		for(int i=arr.length-1; i>=0; i--) {
			max = Math.max(max, arr[i] * size);
			size++;
		}
		
		System.out.println(max);
	}
}


후기 (30min)

가장 적은 중량 * 로프의 개수가 정답이라고 처음에는 생각했는데, 따지고보니 중량 * size 개수만큼이 가질 수 있는 제일 큰 값이었다


Read More

[백준] 포도주 시식 (java) Dynamic_programming

2020-02-25

포도주 시식 (백준 > Dynamic_programming)

문제 링크

문제설명

효주는 포도주 시식회에 갔다. 그 곳에 갔더니, 테이블 위에 다양한 포도주가 들어있는 포도주 잔이 일렬로 놓여 있었다. 효주는 포도주 시식을 하려고 하는데, 여기에는 다음과 같은 두 가지 규칙이 있다.

  1. 포도주 잔을 선택하면 그 잔에 들어있는 포도주는 모두 마셔야 하고, 마신 후에는 원래 위치에 다시 놓아야 한다.
  2. 연속으로 놓여 있는 3잔을 모두 마실 수는 없다.

효주는 될 수 있는 대로 많은 양의 포도주를 맛보기 위해서 어떤 포도주 잔을 선택해야 할지 고민하고 있다. 1부터 n까지의 번호가 붙어 있는 n개의 포도주 잔이 순서대로 테이블 위에 놓여 있고, 각 포도주 잔에 들어있는 포도주의 양이 주어졌을 때, 효주를 도와 가장 많은 양의 포도주를 마실 수 있도록 하는 프로그램을 작성하시오.

예를 들어 6개의 포도주 잔이 있고, 각각의 잔에 순서대로 6, 10, 13, 9, 8, 1 만큼의 포도주가 들어 있을 때, 첫 번째, 두 번째, 네 번째, 다섯 번째 포도주 잔을 선택하면 총 포도주 양이 33으로 최대로 마실 수 있다.

입력

첫째 줄에 포도주 잔의 개수 n이 주어진다. (1≤n≤10,000) 둘째 줄부터 n+1번째 줄까지 포도주 잔에 들어있는 포도주의 양이 순서대로 주어진다. 포도주의 양은 1,000 이하의 음이 아닌 정수이다.

출력

첫째 줄에 최대로 마실 수 있는 포도주의 양을 출력한다.

예제 입력 1 복사

6
6
10
13
9
8
1

예제 출력 1 복사

33


풀이

package Dynamic_programming;

import java.util.*;

//30min
public class beak_포도주시식 {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		int n = sc.nextInt();
		
		int arr[] = new int[n+1];
		int dp[] = new int[n+1];
		
		for(int i=1; i<=n; i++) {
			arr[i] = sc.nextInt();
		}
				
		//1. dp1의 최대는 1잔 마셨을 경우
		dp[1] = arr[1];
		
		//2. dp2의 최대는 -> 1잔 + 2잔
		if(n>1) // n이 1일 수도 있기 때문에, n이 1일때는 arr[2] 없으므로 -> n>1라는 조건 걸어준다.
			dp[2] = arr[1] + arr[2];
		
		//3. dp3 부터는 계산 가능
		//연속으로 0잔 마실 경우 || 연속으로 1잔 || 연속으로 2잔   ->>마신 경우들의 max 값 넣기
		for(int i=3; i<=n; i++) { // i로 초기화했으면 i를 써야지 n을 쓰면 어떡하니!
			dp[i] = Math.max(dp[i-1], Math.max(dp[i-2] + arr[i], dp[i-3] + arr[i-1] + arr[i]));
		}
		
		System.out.println(dp[n]);
	}
}

// https://limkydev.tistory.com/112


후기 (30min)

dp 문제는 항상 어렵다…

  1. 0잔 연속으로 마실 때 -> dp[i-1] // 직전에 가장 많이 마신게 정답
  2. 1잔 연속으로 마실 때 -> dp[i-2] + arr[i] // 현재 마신 잔이 1잔 연속이므로 그 전잔 i-2에 많이 마신거 + 현재
  3. 2잔 연속으로 마실 때 -> dp[i-3] + arr[i-1] + arr[i] // 현재 + 바로직전 + 직전의 전은 안되므로 직전의 전전 dp


tip

  1. 조건을 어떻게 다는지 연습을 계속 해야할 것 같다.


Read More

[백준] 안전 영역 (java) Dfs

2020-02-25

안전 영역 (백준 > Dfs_Bfs)

문제 링크

문제설명

재난방재청에서는 많은 비가 내리는 장마철에 대비해서 다음과 같은 일을 계획하고 있다. 먼저 어떤 지역의 높이 정보를 파악한다. 그 다음에 그 지역에 많은 비가 내렸을 때 물에 잠기지 않는 안전한 영역이 최대로 몇 개가 만들어 지는 지를 조사하려고 한다. 이때, 문제를 간단하게 하기 위하여, 장마철에 내리는 비의 양에 따라 일정한 높이 이하의 모든 지점은 물에 잠긴다고 가정한다.

어떤 지역의 높이 정보는 행과 열의 크기가 각각 N인 2차원 배열 형태로 주어지며 배열의 각 원소는 해당 지점의 높이를 표시하는 자연수이다. 예를 들어, 다음은 N=5인 지역의 높이 정보이다.

img

이제 위와 같은 지역에 많은 비가 내려서 높이가 4 이하인 모든 지점이 물에 잠겼다고 하자. 이 경우에 물에 잠기는 지점을 회색으로 표시하면 다음과 같다.

img

물에 잠기지 않는 안전한 영역이라 함은 물에 잠기지 않는 지점들이 위, 아래, 오른쪽 혹은 왼쪽으로 인접해 있으며 그 크기가 최대인 영역을 말한다. 위의 경우에서 물에 잠기지 않는 안전한 영역은 5개가 된다(꼭짓점으로만 붙어 있는 두 지점은 인접하지 않는다고 취급한다).

또한 위와 같은 지역에서 높이가 6이하인 지점을 모두 잠기게 만드는 많은 비가 내리면 물에 잠기지 않는 안전한 영역은 아래 그림에서와 같이 네 개가 됨을 확인할 수 있다.

img

이와 같이 장마철에 내리는 비의 양에 따라서 물에 잠기지 않는 안전한 영역의 개수는 다르게 된다. 위의 예와 같은 지역에서 내리는 비의 양에 따른 모든 경우를 다 조사해 보면 물에 잠기지 않는 안전한 영역의 개수 중에서 최대인 경우는 5임을 알 수 있다.

어떤 지역의 높이 정보가 주어졌을 때, 장마철에 물에 잠기지 않는 안전한 영역의 최대 개수를 계산하는 프로그램을 작성하시오.

입력

첫째 줄에는 어떤 지역을 나타내는 2차원 배열의 행과 열의 개수를 나타내는 수 N이 입력된다. N은 2 이상 100 이하의 정수이다. 둘째 줄부터 N개의 각 줄에는 2차원 배열의 첫 번째 행부터 N번째 행까지 순서대로 한 행씩 높이 정보가 입력된다. 각 줄에는 각 행의 첫 번째 열부터 N번째 열까지 N개의 높이 정보를 나타내는 자연수가 빈 칸을 사이에 두고 입력된다. 높이는 1이상 100 이하의 정수이다.

출력

첫째 줄에 장마철에 물에 잠기지 않는 안전한 영역의 최대 개수를 출력한다.

예제 입력 1 복사

5
6 8 2 6 2
3 2 3 4 6
6 7 3 3 2
7 2 5 3 6
8 9 5 2 7

예제 출력 1 복사

5


풀이

package Dfs_Bfs;
import java.util.*;


//35min
public class beak_안전영역 {

	static int[][] color(int arr[][], int n) {
		
		for(int i=0;i<arr.length; i++) {
			for(int j=0;j<arr.length; j++) {
				if(arr[i][j] <=n)
					arr[i][j] = 0;
			}
		}
		
		return arr;
	}
	
	static void dfs(int arr[][], int x, int y) {
		arr[x][y] =0;
		
		int dx[] = {0,0,1,-1};
		int dy[] = {1,-1,0,0};
		
		for(int i=0; i<4;i ++) {
			int newx = x + dx[i];
			int newy = y + dy[i];
			
			if(newx>=0 && newx<arr.length && newy>=0 && newy<arr.length && arr[newx][newy]!=0)
				dfs(arr,newx,newy);
		}
		
	}
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		int n = sc.nextInt();
		
		int arr[][] = new int[n][n];
		int height [] = new int[101];
		
		int answer = 1; // 전부 물에 잠기지 않을경우는 영역이 1개이기 떄문에 초기화를 0이아니고 1로 해주어야 한다 
		
		for(int i=0;i<n;i++) {
			for(int j=0; j<n;j++) {
				int a = sc.nextInt();
				arr[i][j] = a;
				height[a] = 1;
			}
		}
		
		for(int i=1;i<height.length;i++) {
			if(height[i] == 1) {
				
				int new_arr[][] = new int[n][n]; //arr 배열을 new_arr배열 만들어서 돌려보는 법!
				
				for(int k=0; k<n; k++) {
					for(int l=0; l<n; l++) {
						new_arr[k][l] = arr[k][l]; // new_arr에 arr 넣기 -> 이걸 반복해줘야 arr여러번 사용 가능
					}
				}
				
				new_arr = color(new_arr,i);
				
				int max = 0;
				for(int k=0; k<n; k++) {
					for(int l=0; l<n; l++) {
						if(new_arr[k][l] !=0) {
							dfs(new_arr,k,l);
							max++;
						}
					}
				}//middle for
				
				answer = Math.max(answer, max);
				
			}//if
		}//out for
		
		System.out.println(answer);
		
	}
}


후기 (35min)

원래 있던 배열에 새로운 배열을 계속 넣어서 color()함수를 돌려보는 법을 익혔다! 까먹지 말도록

Read More