자바 공부하기 위해 한번 작성하면서 공부를 해보겠다.

 

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

 

2750번: 수 정렬하기

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000)이 주어진다. 둘째 줄부터 N개의 줄에는 수 주어진다. 이 수는 절댓값이 1,000보다 작거나 같은 정수이다. 수는 중복되지 않는다.

www.acmicpc.net

 

정렬부터 시작했는데, 

먼저 첫 번째는 

Arrays함수를 사용해서 sort함수 이용해서 했다. ㅎㅎㅎㅋㅋㅋㅋ

import java.util.*;

public class Main{
	public static void main(String args[]){
		Scanner scanner = new Scanner(System.in);
		int N= scanner.nextInt();
		int array[] = new int[N];
		for(int i = 0; i<N; i++) {
			array[i]= scanner.nextInt();
		}
		Arrays.sort(array);
		for(int i = 0; i<N; i++)
			System.out.println(array[i]);
	}
}

뭐 함수를 써보긴 해야 하니깐,, 

 

 

두 번째는 

버블 정렬을 사용했다. 

import java.util.*;
//버블 정렬
public class Main{
	public static void main(String args[]){
		Scanner scanner = new Scanner(System.in);
		int N= scanner.nextInt();
		int array[] = new int[N];
		for(int i = 0; i<N; i++)
			array[i]= scanner.nextInt();
		
		for(int i = 0; i<N-1; i++) {
			for(int row = 0, tem = 0; row <N-1-i; row++) {
				if(array[row] > array[row+1]) {
					tem = array[row];
					array[row] = array[row+1];
					array[row+1] = tem;
				}
			}
		}
		for(int i = 0; i<N; i++)
			System.out.println(array[i]);
	}
}

 

선택정렬

package backjoon;

import java.util.*;
//버블 정렬
public class Main{
	public static void main(String args[]){
		Scanner scanner = new Scanner(System.in);
		int N= scanner.nextInt();
		int array[] = new int[N];
		for(int i = 0; i<N; i++)
			array[i]= scanner.nextInt();
		
		for(int i = 1,j; i<N;i++) {
			int compare_num = array[i];
			for(j = i-1; j>=0 && array[j]>compare_num; j--)
				array[j+1] = array[j];
			array[j+1] = compare_num;
			}
		for(int i = 0; i<N; i++)
			System.out.println(array[i]);
	}
}

 

확실히 정렬을 오랜만에 만들어보는데

저학년일 때보다는 낫다,,

 

더 해보자,, 

'study > java' 카테고리의 다른 글

[Tomcat] 설치 및 eclipse 설정  (0) 2022.01.01
JAVA 상속(2)  (0) 2021.12.04
JAVA 상속  (0) 2021.12.04
java Ajax 연습하기  (0) 2020.07.25
jfreechart bar그래프 두 개 그리기  (0) 2020.07.23

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

 

1890번: 점프

첫째 줄에 게임 판의 크기 N (4 ≤ N ≤ 100)이 주어진다. 그 다음 N개 줄에는 각 칸에 적혀져 있는 수가 N개씩 주어진다. 칸에 적혀있는 수는 0보다 크거나 같고, 9보다 작거나 같은 정수이며, 가장

www.acmicpc.net

 

[규칙]

  1. 오른쪽과 아래쪽만 이동 가능
  2. 칸에 적혀져 있는 칸만큼 이동
  3. 0이 나오면 못 감
  4. 경로의 개수는 2^63-1보다 작거나 같음
  5. 경로의 개수 구해라

 

[실패 원인]

  1. 문제를 제대로 안 읽었다. (최단기 거리인 줄,, )
  2. 제일 간단한 DFS로 푸니깐 시간 초과가 났다.
  3. 경로의 개수가 2^63-1보다 작거나 같다 == int형으로는 안된다. 

 

[풀이 설명]

DFS로 푼 것이랑 원리는 비슷한데

반복문을 통해 풀었다. 

  • 따른 배열을 만들어서
  • route [0][0] 배열에는 1을 저장한다. 
  • 각 행열을 다 지나치면서
    • 0이 아니거나, 배열 만든 것(route)이 0이 아니면
    • 가로, 세로에 각 칸에 있는 칸만큼 더해서 더한다. 

 

 

이렇게 경로를 저장할 수 있다. 

 

 

 

 

 

 

[소스코드]

#include<iostream>
using namespace std;

int N;
int input_array[101][101];
long long route[101][101] = { 0 };

int main() {
	cin >> N;
	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			cin >> input_array[i][j];
	
	route[0][0] = 1;
	for(int row = 0; row<N; row++)
		for (int col = 0; col < N; col++) {
			if (input_array[row][col] != 0 && route[row][col]!= 0) {
				if (row + input_array[row][col] < N)
					route[row + input_array[row][col]][col] += route[row][col];
				if (col + input_array[row][col] < N)
					route[row][col + input_array[row][col]] += route[row][col];
			}
		}
	cout << route[N-1][N-1];
	return 0;
}

 

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

 

11055번: 가장 큰 증가 부분 수열

수열 A가 주어졌을 때, 그 수열의 증가 부분 수열 중에서 합이 가장 큰 것을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {1, 100, 2, 50, 60, 3, 5, 6, 7, 8} 인 경우에 합이 가장 큰 증가 부분 수

www.acmicpc.net

 

 

[규칙]

  1. 증가 부분 수열
  2. 합이 가장 큰 것

 

[실패 원인]

  1. 알고리즘은 간단하였는데, 비교하는 부분에서 합이 큰 값이랑 비교를 안 하고 자신과 작은 값의 수열과 비교해서 틀렸다.

 

[풀이 설명]

  • 증가하면서 합이 가장 큰 것을 선택하면 된다. 
  • 나는 배열을 따로 만들어서, 각자 증가하는 부분에 있어서 합을 각 행마다 저장을 했다. 
  • 이게 무슨 말이라면, 
  •  

자신보다 작은 값의 최댓값과 자신을 더하면 된다고 생각했다. 

ex) 50은 자신보다 작은 값이 1과 2가 있다. 

그치만 2는 1을 이미 더한 값이기 때문에 2의 값만 더해주면 된다. (연한 주황색 화살표 참조)

 

[소스코드]

#include<iostream>
#include <vector>
#include<algorithm>
using namespace std;

int main() {
	int N, output_max_num = 0;

	cin >> N;
	vector<int> input_A(N + 1), add_array(N+1,0);
	
	for (int i = 0; i < N; i++)
		cin >> input_A[i];

	for (int i = 0, max_add_num; i < N; i++) {
		max_add_num = 0;
		for (int j = 0; j < i; j++) {
			if (input_A[i] > input_A[j])
				max_add_num = max(max_add_num, add_array[j]);
		}
		add_array[i] = input_A[i] + max_add_num;
		output_max_num = max(output_max_num, add_array[i]);
	}
	cout << output_max_num;
	
	return 0;
}

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

 

22857번: 가장 긴 짝수 연속한 부분 수열 (small)

수열 $S$에서 최대 $K$번 원소를 삭제한 수열에서 짝수로 이루어져 있는 연속한 부분 수열 중 가장 긴 길이를 출력한다.

www.acmicpc.net

 

[규칙]

  1. 수열에서 K번 삭제 가능
  2. 삭제 후 짝수로 이루어져 있는 연속한 부분 수열 
  3. 연속한 부분 수열

 

[실패 원인]

  1. 부분 수열에 대해 내가 잘 몰랐다. 
    • array = [1,2,3,4,5,6,7]
      • 연속된 부분 수열 : {1}, {2}, {3}, {4], {5} ,.... {1,2}, {2,3},.... {1,2,3,4},....

 

[풀이 설명]

  • 최대한 포인터를 사용하지 않고 해 보았다. 
  • 어차피 연속된 부분 수열이기 때문에, 짝수부터 시작해야 한다고 생각했다.
    1. 짝수 시작 점부터 짝수 개수를 센다.
    2. 홀수가 나오면 홀수 개수를 센다 (세고 있던 짝수 수는 초기화한다.)
    3. 배열에 짝수, 홀수 수를 각각 넣는다. 
  • 홀수의 개수가 들어있는 배열을 이용한다.
    1. 홀수의 개수가 들어있는 배열 0번째부터 더해서 K가 넘을 때까지 반복한다.
      • 반복하면서 짝수의 개수를 더한다.

간단하게 적었지만, 설명이 제대로 안 된 것 같아 그림을 그려서 설명해보자면

위의 그림처럼 노란색 밑줄은 짝수, 초록색 밑줄은 홀수이다.

짝수와 홀수가 연속된 부분을 개수를 세어 각각 배열에 넣은 모습이다. 

 

문제에서 원소를 K번 삭제하기 때문에 odd의 수가 K번 보다 작어야 한다. 

  • 예를 들면 k가 2라면
    • odd배열에서 2보다 작거나 같게 반복하면서
    • even배열을 더해준다.
    • 그렇게 되면 2 + 3으로 젤 긴 수열은 5가 된다. 

 

  • 다른 예시를 들어보면

K = 5 일 때,

odd가 2와 3을 선택을 해야

젤 큰 길이를 가지는 4 + 6 +5가 된다. 

 

 

[코드]

#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main() {
	int N, K;
	int odd_row = 0;
	cin >> N >> K;
	vector<int> even(N+1), odd(N+1);
	
    //odd, even배열에 넣기
	for (int i = 0,num, even_start =0,even_row = 0; i < N; i++) {
		cin >> num;
		if (even_start == 0 && num % 2 == 0)even_start = 1;
		if (even_start == 1) {
			if (num % 2 == 0) {
				even[even_row] += 1;
				if(odd[odd_row] > 0)odd_row++;
			}
			else {
				odd[odd_row] += 1;
				if (even[even_row] > 0)even_row++;
			}
		}
	}
    
    //최댓값 구하기
	int max_sum = 0;
	for (int i = 0, sum; i <= odd_row; i++) {
		sum = 0;
		for (int j = i, count = 0;  j <= odd_row; j++) {
			count += odd[j];
			if (count <= K)	sum += even[j];
			else { 
				sum += even[j]; 
				break; 
			}
		}
		max_sum = max(max_sum, sum);
	}
	cout << max_sum;
	return 0;
}

 

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

 

1932번: 정수 삼각형

첫째 줄에 삼각형의 크기 n(1 ≤ n ≤ 500)이 주어지고, 둘째 줄부터 n+1번째 줄까지 정수 삼각형이 주어진다.

www.acmicpc.net

 

[규칙]

1. 맨 위의 층부터 시작

2. 아래의 있는 수 중 최대가 되는 경로 찾기

3. 대각선 왼쪽 또는 오른쪽에 있는 것만 선택 가능

4. 삼각형 크기 500이하

5. 시간제한 2초

 

[실패 원인]

  • 이것도 마찬가지로 마음 편하게 DFS로 풀었더니 시간 초과가 났다. 
    • 시간이 2초나 되는데 오류가 난 것이다. ㅋㅎㅋㅎ, 세상에,,,
    • 그래서 백준의 '질문 검색'버튼을 이용해서 다른 분들도 시간 초과가 났나 보았다. 
    • 보니깐 문제가 '메모이제이션(Memoization) 을 이용해야 한다고 한다. 

 

[풀이 설명]

  • 먼저 마지막 행 위의 행부터 시작하기로 했다. 
    • n-2행부터
      • 자기 아래의 값, 아래 +1 값 중 큰 값을 자신과 더했다
      • 옆에 그림을 보면 알 수 있다. 
      • 첫 번째를 설명해보면, 젤 마지막 행에서 4와 5중에서는 5가 크므로, 2(자기 자신)과 5를 더해준다. 
      • 이렇게 0번째 행까지 해준다. 

 

[소스 코드]

#include <iostream>
#include<algorithm>
using namespace std;

int main() {
	int n; //삼각형의 크기 
	int Triangle[501][501];
	int max_num = 0;
	cin >> n;
	for (int i = 0; i < n; i++)
		for (int j = 0; j <= i; j++)
			cin >> Triangle[i][j];

	for (int row = n - 2; row >= 0; row--)
		for (int col = 0; col <= row; col++)
			Triangle[row][col] += max(Triangle[row + 1][col], Triangle[row + 1][col + 1]);

	cout << Triangle[0][0];

	return 0;
}

 

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

 

2579번: 계단 오르기

계단 오르기 게임은 계단 아래 시작점부터 계단 꼭대기에 위치한 도착점까지 가는 게임이다. <그림 1>과 같이 각각의 계단에는 일정한 점수가 쓰여 있는데 계단을 밟으면 그 계단에 쓰여 있는 점

www.acmicpc.net

 

[규칙]

1. 계단은 한 번에 한 칸 or 두 칸

2. 연속 세 칸  X

3. 마지막 도착 계단은 반드시 밟아야 함

4. 총 점수의 최댓값 구하기

 

[실패 원인]

1. DFS로 푸는 게 젤 안전할 것 같아서 풀었는데 시간 초과가 나왔다. 

- 아마 제한시간이 1초여서 계단의 수가 300 이하이지만, 시간이 부족한 것 같았다. 

2. DFS 말고 아래 설명할 알고리즘으로 풀었는데, 세번째 칸이 무조건 (첫 번째 계단 + 세 번째 계단) 값인 줄 알았는데 문제를 잘 보니 

이렇게 시작점은 포함되지 않기 때문에,(첫 번째 계단 + 세 번째 계단) OR(두 번째 계단 최댓값 + 세 번째 계단)의 최댓값이 세 번째 계단 값이었다. 

 

[풀이 설명]

DFS가 실패한 뒤, 실패한 이유는 시간 초과여서 '그럼 반복하여 배열을 이용해서 해보자'라는 생각을 하게 되었다. 

순서대로 생각을 해보면, 

 

º 첫 번째 계단은 1번째 계단 값

º 두 번째 계단은 1번째 계단 + 2번째 계단

º 세 번째 계단은

    (1번째 계단 + 3번째 계단) 

            OR

    (1번째 계단 + 2번째 계단+ 3번째 계단) : 시작점은 연속된 세 개의 계단을 밟아서는 안된다는 조건에 빠지기 때문

º 네 번째 계단은

    (1번째 계단 + 3번째 계단 + 4번째 계단) 

            OR

    (1번째 계단 + 2번째 계단+ 4번째 계단)

º 다섯 번째 계단은

    (2번째 계단 + 4번째 계단 + 5번째 계단) 

            OR

    (3번째 계단+ 5번째 계단) 

이렇게 된다.

 

 

그래서 식을 생각해보면

X자리의 최댓값을 구하려면

X자리 계단 값 + X-2의 최댓값

X자리 계단 값 + X-1의 계단 값 + X-3의 최댓값

이라는 식이 나온다.

 

그렇지만 X-1은 왜 계단 값을 구하냐

이것은 옆의 판을 보면 알 수 있다. 

5번의 계단의 최댓값을 구할 시

2번, 4번, 5번 이렇게 뛰어넘는다고 생각하면

4번째 계단은 무조건 앞에 3번을 포함하지 않아야 한다. 

4번째 계단의 최댓값을 구한다면, 3번이 포함할 수 있기 때문에 사용하지 않는다. 

 

 

이렇게 소스코드를 짜면,

#include <iostream>
#include<algorithm>
using namespace std;


int main() {
	int N;
	int score[301];
	int max_score[301];

	cin >> N;
	for (int i = 0; i < N; i++)
		cin >> score[i + 1];

	max_score[1] = score[1];
	max_score[2] = score[1] + score[2];
	max_score[3] = max(score[2]+score[3],score[1] + score[3]);

	for (int i = 4; i <= N; i++) {
		max_score[i] = max(score[i] + max_score[i - 2], max_score[i - 3] + score[i - 1] + score[i]);
	}
	cout << max_score[N];
	return 0;
}

 

나온다. 

 

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

 

9237번: 이장님 초대

입력은 두 줄로 이루어져 있다. 첫째 줄에는 묘목의 수 N (1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄에는 각 나무가 다 자라는데 며칠이 걸리는지를 나타낸 ti가 주어진다. (1 ≤ ti ≤ 1,000,000)

www.acmicpc.net

 

 

일단 첫 번째 시도를 실패했는데 

문제를 잘못 읽었다.

나무 심는 순서를 신중하게 골라서 최대한 빨리 초대하려고 한다

 

심는 순서를 내가 정하는 것이었다!!!

차례대로인 줄

문제를 잘 읽자.

 

먼저, 최대한 빨리 초대하려고 하니깐,

정렬을 했다.

 

정렬하고 나서 묘묙 하나를 심는데 걸리는 시간이 1일 걸린다고 했다.

그러니 심는데 시간이 1일이 걸린다고 먼저 더하고 시작해야 하는 것이다. 

 

 

정리해보자면, 

만약 묘목 자라는데 걸리는 시간이 5 9 8 2라고 하자.

정렬하면

2 5 8 9이다. 

그럼 빨리 초대하려고 하니깐. 

그럼 묘목 자라는데 걸리는 시간이 9일 걸리는 묘목부터 심어야 한다.

 

그런데 묘목 심는데 걸리는 시간이 1일이니깐,

9일 걸리는 묘목을 심는 데는 1+9일이 걸리고 

이장님을 초대하는데 다음날 초대하니깐 

결과는 9 +2일이 걸리는 것이다.

 

이렇게 더하면

2 5 8 9 묘목은

+ 5 4 3 2

 7 9 11 11일 걸린다. 

 

그럼 최댓값은 11일.

최대 11일이 걸린다. 

 

소스코드는 

#include <iostream>
#include <algorithm>
using namespace std;


int main() {
	int count;
	int max_num = 0;
	int input[100001];
	cin >> count;

	for (int i = 0,num; i < count; i++) {
		cin >> input[i];
	}
	sort(input, input + count);

	for (int i = count - 1,add =2; i >= 0; i--) {
		max_num = max(input[i] + add, max_num);
		add++;
	}
	cout << max_num;
	return 0;
}

www.acmicpc.net/problem/2304

 

2304번: 창고 다각형

첫 줄에는 기둥의 개수를 나타내는 정수 N이 주어진다. N은 1 이상 1,000 이하이다. 그 다음 N 개의 줄에는 각 줄에 각 기둥의 왼쪽 면의 위치를 나타내는 정수 L과 높이를 나타내는 정수 H가 한 개의

www.acmicpc.net

 

이건 알고리즘 공부하기 전에 말도 안 되게 짰다가

틀려서 다시 오랜만에 시도한 문제이다.

c++ 중에 map이라는 걸 사용할 것이다.

map은 key값과 value가 한 쌍으로 되어있는 컨테이너이다.

 

 

알고리즘
1. map에 넣는다 (위치, 높이)
   1-1). map에 넣으면서 높이가 젤 큰 값을 구한다. (위치도 젤 큰 값)
   1-2). map에 넣으면서 마지막 위치를 구한다.

2. iterater를 이용하여 map의 젤 앞의 위치와 높이를 저장하고 iter를 map의 두 번째 위치로 바꾼다.

3. iter를 1-1)에서 구한 젤 큰 위치 값까지 for을 돌린다.
   3-1). 앞의 높이가 현재 가리키고 있는 iter의 높이보다 작거나 같으면
          사각형의 넓이를 더해준다.
          앞의 위치를 현재 위치, 앞의 높이를 현재 높이로 대입한다.

4. 젤 큰 값은 앞의 for문으로 돌리지 않았기 때문에 높이만 더해준다(넓이가 1이라서)

5. iter를 lower_bound를 이용하여 1-2)에서 구한 마지막 위치로 가리킨다.

6. iter를 이용하여 젤 뒤의 위치와 높이를 저장하고 iter를 map의 뒤에서 두번째 위치로 바꾼다.

7. iter를 1-1)에서 구한 젤 큰 위치 값까지 for문 돌린다.
   7-1). 뒤의 높이가 현재 가리키고 있는 iter의 높이보다 작으면 
          사각형의 넓이를 더해준다.
          뒤의 위치를 현재위치, 뒤의 높이를 현재 높이로 대입한다.

8. 넓이를 출력

 

 

위 그림식으로 끝에서 젤 큰 높이를 향하여 더해준다.

 

이 문제에서의 반례는

이러한 상황이다. 최대의 높이가 두개 이상일 경우,

이 반례를 생각하지 않는다면 최대 높이만 구하여한다면 틀린다. 

나도 그렇게 틀렸었다.

 

소스 코드

#include<iostream>
#include<map>
using namespace std;

int main() {
	map<int, int> m;
	int testcase;
	int row, hight;
	int max_row = 0, max_hight = 0;
	int sum = 0;
	int last_row = 0;
	cin >> testcase;
	while (testcase--) {
		cin >> row >> hight;
		m.insert(pair<int, int>(row, hight));
		if (max_hight <= hight) {
			max_hight = hight;
			max_row = row;
		}
		if (last_row < row) {
			last_row = row;
		}
	}

	map<int, int>::iterator iter;
	iter = m.begin();
	int my_row = iter->first;
	int my_hight = iter->second;
	iter++;
	for (; my_row != max_row; iter++) {
		if (my_hight <= iter->second) {
			sum += (iter->first - my_row) * my_hight;
			my_row = iter->first;
			my_hight = iter->second;
		}
		
	}
	sum += my_hight;
	
	iter = m.lower_bound(last_row);

	my_row = iter->first;
	my_hight = iter->second;
	iter--;
	for (; my_row != max_row; iter--) {
		if (my_hight <= iter->second) {
			sum += (my_row - iter->first) * my_hight;
			my_row = iter->first;
			my_hight = iter->second;
		}
	}
	cout << sum;
	return 0;
}

'Coding Test > Problem_solving' 카테고리의 다른 글

[백준] 11399_ATM (python, c++)  (0) 2021.06.28
[백준] 9237_이장님 초대 (c++)  (0) 2021.06.16
[백준] 1373_2진수 8진수 (c++)  (0) 2021.03.11
[백준] 10808 알파벳 개수  (0) 2021.03.09
[백준] 1874_스택 수열  (0) 2021.02.18

+ Recent posts