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

 

1012번: 유기농 배추

차세대 영농인 한나는 강원도 고랭지에서 유기농 배추를 재배하기로 하였다. 농약을 쓰지 않고 배추를 재배하려면 배추를 해충으로부터 보호하는 것이 중요하기 때문에, 한나는 해충 방지에 

www.acmicpc.net

 

문제 설명

해충 방지에 효과적인 배추흰지렁이를 구입하기로 한다.

이 지렁이는 배추근처에 서식하며 해충을 잡아 먹음으로써 배추를 보호한다.

어떤 배추에 배추흰지렁이가 한마리라도 살고 있으면 이 지렁이는 인접한 다른 배추로 이동할 수 있다.

한 배추의 상하좌우 네 방향에 다른 배추가 위치한 경우 인접해 있는 것이다.

0은 배추가 심어져 있지 않은 땅이고, 1은 배추가 심어져 있는 땅을 나타낸다.

배추흰지렁이 마리 수를 출력한다.

 

풀이

  • 입력받은 배추밭의 가로길이 M과 세로길이 N -> 2차원 배열로 구성
  • 배추가 심어져 있는 위치의 개수 K -> K개의 좌표점은 1로 입력받고 나머지 좌표는 0으로 구성한다.
  • 해당 좌표점이 1이면 DFS를 이용하여 상하좌우가 1인지 살펴보며 1인경우 0으로 값을 바꾼다.
    • 이때 상하좌우의 좌표점은 0이상 가로길이 M 세로길이 N 이하여야 한다. ( 좌표상을 벗어나서는 안된다는 뜻 )
  • 이 dfs 함수가 끝나면 해당 좌표의 상하좌우 탐색이 끝났기 때문에 벌레 갯수를 하나 더해준다.

Python

import sys
sys.setrecursionlimit(10000)
input = sys.stdin.readline

t = int(input())

def dfs(x, y):
    dx = [0, 0, -1, 1]
    dy = [1, -1, 0, 0]
	
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        # 이때 상하좌우의 좌표점은 0이상 가로길이 M 세로길이 N 이하여야 한다. ( 좌표상을 벗어나서는 안된다는 뜻 )
        if (0 <= nx < m) and (0 <= ny < n):
            if graph[ny][nx] == 1:
            	# 해당 좌표점이 1이면 DFS를 이용하여 상하좌우가 1인지 살펴보며 1인경우 0으로 값을 바꾼다.
                graph[ny][nx] = 0
                dfs(nx, ny)

for _ in range(t):
    m, n, k = map(int, input().split()) # m 가로 / n 세로
    # 배추가 심어져 있는 위치의 개수 K -> K개의 좌표점은 1로 입력받고 나머지 좌표는 0으로 구성한다.
    graph = [[0 for _ in range(m)] for _ in range(n)]
    cnt = 0
    
    for _ in range(k):
        x, y = map(int, input().split())
        graph[y][x] = 1
    for x in range(m):
        for y in range(n):
            if graph[y][x] == 1:
                dfs(x, y)
                cnt += 1
    print(cnt)

Java

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

// 1012번. 유기농 배추
public class Baekjoon_1012 {
    static int cnt;
    static int m,n,k;
    static int[][] graph;
    public static void dfs(int x, int y){
        int[] dx = {0, 0, -1, 1};
        int[] dy = {1, -1, 0, 0};

        for (int i = 0; i < 4; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];
            if((0 <= nx && nx < m) && (0 <= ny && ny < n)){
                if(graph[ny][nx] == 1){
                    graph[ny][nx] = 0;
                    dfs(nx, ny);
                }
            }
        }

    }
    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        int t = Integer.parseInt(bf.readLine());
        for (int i = 0; i < t; i++) {
            StringTokenizer st = new StringTokenizer(bf.readLine(), " ");
            m = Integer.parseInt(st.nextToken());
            n = Integer.parseInt(st.nextToken());
            k = Integer.parseInt(st.nextToken());

            graph = new int[n][m];
            cnt = 0;

            for (int j = 0; j < k; j++) {
                st = new StringTokenizer(bf.readLine(), " ");
                int x = Integer.parseInt(st.nextToken());
                int y = Integer.parseInt(st.nextToken());
                graph[y][x] = 1;
            }

            for (int x = 0; x < m; x++) {
                for (int y = 0; y < n; y++) {
                    if(graph[y][x] == 1){
                        dfs(x, y);
                        cnt++;
                    }
                }
            }
            System.out.println(cnt);
        }
        
    }
}

 

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

 

1011번: Fly me to the Alpha Centauri

우현이는 어린 시절, 지구 외의 다른 행성에서도 인류들이 살아갈 수 있는 미래가 오리라 믿었다. 그리고 그가 지구라는 세상에 발을 내려 놓은 지 23년이 지난 지금, 세계 최연소 ASNA 우주 비행

www.acmicpc.net

문제 설명

x -> y까지 도달하는데 필요한 최소한의 공간이동 장치 작동 횟수를 출력한다.

예를 들어 0,3 까지 가기 위해서 1,1,1 총 3번의 공간이동이 필요하다.

 

여기서 주의할 점이 몇가지 있다.

  • 시작할때와 도착하기전에는 무조건 1광년만 이동이 가능하다.
  • 처음 작동시킬 경우 -1 0 1 만큼만 이동이 가능하다. 
    • 그 다음으로 0 1 2 광년을 이동 할 수 있다.
    • 그 다음 2광년 이동한다면 다음 이동가능한 광년은 1 2 3 이다
  • 그렇다면 거리가 11이라면 어떻게 이동해야할까?
    • 1,2,3,4,1 이렇게는 이동 불가능하다.
    • 1,2,3,2,2,1 으로 이동이 가능하다.
      • 처음 1광년만 이동이 가능하다 -> 남은 거리 10
      • (남은 거리 10) 1광년 이동했다면 다음으로는 0,1,2 이동 가능하다 (2 선택) 10-2
      • (남은 거리 8) 2광년 이동했다면 다음으로는 1,2,3 이동 가능하다 (3 선택) 8-3
      • (남은 거리 5) 3광년 이동했다면 다음으로 2,3,4 이동 가능하다 (4 선택) -> 5-4
      • (남은 거리 1 ) 4광년 이동했다면 다음으로 3,4,5 이동 가능하다.
        • 마지막은 1광년만 이동이 가능하다 
          • 4를 선택하면 다음도 3,4,5 거리만 이동 가능하다. -> 이동이 불가하다.
          • 3을 선택하면 다음 움직일 수 있는거리는 2,3,4 이다.  -> 이동이 불가하다.
          • 숫자를 줄여야 한다.
      • 다시 남은 거리 5로 돌아가보자 4가 아닌 2를 선택한다. (2 선택) 5-2
      • (남은 거리 3) 2광년 이동했다면 다음으로 1,2,3 이동가능하다. (2선택) 3-2
      • (남은 거리 1) 거리가 1이 남았으며 마지막은 1광년만 이동가능하다에 적합하다.

 

표로 다시 정리해보자 거리가 1부터 16까지 정리해보았다.

Distance와 max의 관계

Distance move Count max
1 1 1 1
2 11 2 1
3 111 3 1
4 121 3 2
5 1211 4 2
6 1221 4 2
7 12211 5 2
8 12221 5 2
9 12321 5 3
10 123211 6 3
11 123221 6 3
12 123321 6 3
13 1233211 7 3
14 1233221 7 3
15 1233321 7 3
16 1234321 7 4

여기서 주목할점은 파란색 부분이다.

Distance 4 일때 max = 2가 된다.

Distance 9 일때 max = 3이 된다.

Distance 16 일때 max = 4가 된다.

 

어떤게 떠오르지 않는가? 루트이다. 16의 루트는 = 4가 된다. 

그렇다면 Distance 25면 max = 5가 되는 것이다.

 

Code

max = int(math.sqrt(distance))
    if max == math.sqrt(distance):
        print(2 * max -1)

cnt 변화

Distance Count max
1 1 1
2 2 1
3 3 1
4 3 2
5 4 2
6 4 2
7 5 2
8 5 2
9 5 3
10 6 3
11 6 3
12 6 3
13 7 3
14 7 3
15 7 3
16 7 4
  • 규칙1 : max가 1씩 증가할때마다 cnt의 값이 두번씩 바뀌고 있다.
  • 규칙2 : max가 1씩 증가할때 cnt의 값이 변한다.
    • max 값이 변할 때는 cnt는 다음 공식을 만들 수 있다.
      • cnt = (max * 2) -1
      • max = 3일때 cnt 5가 된다.
      • max = 4일때 cnt 7이 된다.
  • 규칙3 : max의 값만큼 cnt가 반복된다.
    • cnt가 4에서 5로 될때 2번만에 값이 바뀐다.
    • cnt가 6에서 7로 될때 3번만에 값이 바뀐다.

10~12(max * max < distance <= max * max + max) 까지 cnt는 2 * max가 된다.

13~15 까지 cnt는 2 * max + 1이 된다.

 

Code

    elif distance <= (max * max + max):
        print(2 * max)
    else:
        print(2 * max+1)

 

 


전체코드

import math
import sys

input = sys.stdin.readline

def fun2(distance):
    max = int(math.sqrt(distance))
    if max == math.sqrt(distance):
        print(2 * max -1)
    elif distance <= (max * max + max):
        print(2 * max)
    else:
        print(2 * max+1)
    return


T = int(input())
for case in range(T):
    x, y = map(int, input().split())
    fun2(y-x)

 

 

Reference


https://st-lab.tistory.com/79

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

 

1002번: 터렛

각 테스트 케이스마다 류재명이 있을 수 있는 위치의 수를 출력한다. 만약 류재명이 있을 수 있는 위치의 개수가 무한대일 경우에는 $-1$ 출력한다.

www.acmicpc.net

 

이 문제는 원에 대해서 알아야 쉽게 풀 수 있는 문제이다.

원에 대해 알아보며 코드를 작성해보자

두 점 사이의 거리 공식

Python Code

distance = (x2 - x1)**2 + (y2 - y1)**2
distance = math.sqrt(distance)

두 원의 위치 관계

1. 만나지 않는 경우

  • 외부에서 만나지 않음
    • r1 + r2 < d 인 경우

  • 내부에 포함
    • r1 - r2 > d인 경우

  • 동심원
    • d == 0 인 경우

 

코드를 작성해보면 다음과 같다

Python Code

    elif r1 + r2 < distance or abs(r2-r1) > distance or distance == 0:
        # 두 원이 서로 밖에 있으면 만나지 않을때 / 다른 원의 내부에 있으면 만나지 않는다. / 동심원인 경우
        print(0)

2. 접하는 경우(한 점에서 만나는 경우)

  • 외접
    • r1 + r2 = d

  • 내접
    • r1 - r2 = d or r2 - r1 = 0

Python Code

    elif r1 + r2 == distance or abs(r2-r1) == distance:
        # 두원이 외접할때 or 내접할때
        print(1)

 


3. 두 점에서 만나는 경우

  • r1 - r2 < d < r1 - r2

Python Code

    elif abs(r2-r1) < distance < abs(r2+r1):
        print(2)

마지막으로 문제에서 조건이 하나 더 있었는데

" 만약 류재명이 있을 수 있는 위치의 개수가 무한대일 경우 -1을 출력한다"

이 의미는 서로 x,y 좌표가 같고 반지름또한 같으면 원이 겹치게 된다. 코드로 표현하면 다음과 같다.

    if x1 == x2 and y1 == y2 and r1 == r2:
        print(-1)

 


전체코드

input = sys.stdin.readline

n = int(input())

for case in range(n):
    x1, y1, r1, x2, y2, r2 = map(int, input().split())
    distance = (x2 - x1)**2 + (y2 - y1)**2
    distance = math.sqrt(distance)
    if x1 == x2 and y1 == y2 and r1 == r2:
        print(-1)
    elif r1 + r2 < distance or abs(r2-r1) > distance or distance == 0:
        # 두 원이 서로 밖에 있으면 만나지 않을때 / 다른 원의 내부에 있으면 만나지 않는다. / 동심원인 경우
        print(0)
    elif r1 + r2 == distance or abs(r2-r1) == distance:
        # 두원이 외접할때 or 내접할때
        print(1)
    elif abs(r2-r1) < distance < abs(r2+r1):
        print(2)
  • abs를 사용한 이유 : 입력받는 반지름이 r1이 큰지 r2가 큰지 모르기 때문에 abs로 절댓값을 사용한다. 반지름은 0보다 항상 큰 값을 가진다는 것도 명심해둘것

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

 

2667번: 단지번호붙이기

<그림 1>과 같이 정사각형 모양의 지도가 있다. 1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다. 철수는 이 지도를 가지고 연결된 집의 모임인 단지를 정의하고, 단지에 번호를 붙이려 한다. 여

www.acmicpc.net

 

풀이

  • 입력받은 배열에 1이 있다면 dfs 함수를 호출합니다.
  • x,y의 인덱스가 n보다 크거나 0보다 작아지면 배열 범위를 벗어나기 때문에 return을 합니다.
  • x,y 좌표에 1이 있다면 count을 증가시킵니다. -> 1의 갯수를 셉니다.
  • 위,아래,오른쪽,왼쪽을 확인하며 1이 있는지 확인합니다.
  • 1이 있다면 다시 dfs을 호출합니다.
import sys

input = sys.stdin.readline

N = int(input())
dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]

result = []
count = 0
def dfs(x, y):
    global count

    if x < 0 or x >= N or y < 0 or y >= N:
        return

    if maps[x][y] == '1':
        count += 1
        maps[x][y] = '0'
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            dfs(nx, ny)

maps = list()
for i in range(N):
   maps.append(list(input()))

for i in range(N):
    for j in range(N):
        if maps[i][j] == '1':
            dfs(i, j)
            result.append(count)
            count = 0

result.sort()
print(len(result))
for k in result:
    print(k)

https://leetcode.com/problems/letter-combinations-of-a-phone-number/

문제 설명:

2에서 9까지 숫자가 주어졌을 때 전화번호로 조합 가능한 모든 문자를 출력하는 문제

이 문제는 전체를 탐색해서 푸는 조합 문제이다.

dic = {
        "2": "abc",
        "3": "def",
        "4": "ghi",
        "5": "jkl",
        "6": "mno",
        "7": "pqrs",
        "8": "tuv",
        "9": "wxyz",
        "0": "+"
    }

자판기에 다음과 같이 있다고 했을때

'23' 을 입력받으면 'ad' , 'ae', 'af', 'bd', 'be', 'bf', 'cd', 'cd', 'cf' 3*3 = 9개 출력을 하면 된다.

 

풀이

  • path = '' 를 정의하고 path 길이와 입력받은 문자열(ex. 23)의 길이가 같아지면 재귀함수를 종료 할 것이다.
  • 입력받은 문자열이 없다면 빈 리스트를 반환한다.
  • dic['2'] 는 'abc'가 들어있다. 
    • a를 포함한 path와 입력받은 문자열의 다음 인덱스를 넘겨 재귀호출을 해준다.
      • ex) 23을 입력받았다면 1번 인덱스, a 를 넘겨 다시 재귀함수형태로 호출한다.
class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        def dfs(index, path):
            if len(digits) == len(path):
                result.append(path)
                return

            for digit in dic[digits[index]]:
                dfs(index+1, path+digit)

        if not digits:
            return []
        dic = {
            "2": "abc",
            "3": "def",
            "4": "ghi",
            "5": "jkl",
            "6": "mno",
            "7": "pqrs",
            "8": "tuv",
            "9": "wxyz",
            "0": "+"
        }
        result = []
        dfs(0, "")
        return result

 

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

 

15650번: N과 M (2)

한 줄에 하나씩 문제의 조건을 만족하는 수열을 출력한다. 중복되는 수열을 여러 번 출력하면 안되며, 각 수열은 공백으로 구분해서 출력해야 한다. 수열은 사전 순으로 증가하는 순서로 출력해

www.acmicpc.net

문제 설명

예제2 출력 결과를 보면 조합이라는 것을 바로 알 수 있다.

1 2
1 3
1 4
2 3
2 4
3 4

 

풀이설계

파이썬 itertools모듈의 combinations 를 사용하면 금방 풀 수 있다.

 


import sys
from itertools import combinations

input = sys.stdin.readline
n, m = map(int, input().split())
lst = [i for i in range(1,n+1)]
for ele in combinations(lst, m):
    #print(str(list(ele)).replace("[", "").replace("]", "").replace(",", ""))
    print(*ele)

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

 

12015번: 가장 긴 증가하는 부분 수열 2

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000,000)

www.acmicpc.net

문제 설명:

 

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성

예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {1020, 10, 30, 20, 50} 이고, 길이는 4이다.

 

풀이설계

  • 리스트에서 val을 하나씩 꺼내온다.
    • dp[-1]는 보다 val이 크다면 뒤에 바로 추가해준다.
    • 그렇지 않다면 이분탐색(bisect_left)을 이용하여 어디에 추가할지 인덱스를 정하고 val을 추가한다.
import sys
from bisect import bisect_left


input = sys.stdin.readline
n = int(input())
lst = list(map(int, input().split()))
dp = [0]

for val in lst:
    if dp[-1] < val:
        dp.append(val)
    else:
        dp[bisect_left(dp, val)] = val

print(len(dp)-1)

 

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

 

2108번: 통계학

첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 단, N은 홀수이다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다.

www.acmicpc.net

 

문제설명

  1. 산술평균 : N개의 수들의 합을 N으로 나눈 값
  2. 중앙값 : N개의 수들을 증가하는 순서로 나열했을 경우 그 중앙에 위치하는 값
  3. 최빈값 : N개의 수들 중 가장 많이 나타나는 값
  4. 범위 : N개의 수들 중 최댓값과 최솟값의 차이

 

풀이설계

  1.  산술형은 sum / 반올림은 round
  2. 중앙값은 배열의 중앙값 // 2
  3. 최빈값
    1. 배열의 길이가 1 이하인 경우 0번째 값 출력
    2. 배열의 길이가 1 초과인 경우 Counter 최빈값을 계산한뒤 역순으로 정렬해서 
      1. 첫번째값과 0번째 value 값을 비교해서 값이 같다면 첫번째 값을 출력
      2. 그렇지않다면 0번째 값을 출력한다.
  4. 범위 0번째와 가장 끝에 있는 값의 차이를 계산

 

import sys
from collections import Counter

input=sys.stdin.readline

n = int(input())
nums = [int(input()) for _ in range(n)]
nums.sort()

print(round(sum(nums) / n))  # 산술평
print(nums[(len(nums)) // 2])

if len(nums) <= 1:
    print(nums[0])
else:
    cnts = sorted(Counter(nums).items(), key=lambda x: x[1], reverse=True)
    if cnts[0][1] == cnts[1][1]:
        print(cnts[1][0])
    else:
        print(cnts[0][0])

print(nums[n-1] - nums[0])

+ Recent posts