티어 : Silver 5 시간 제한 : 1 초 메모리 제한 : 128 MB 알고리즘 분류 : 수학, 정수론, 소수 판정
문제
자연수 M과 N이 주어질 때 M이상 N이하의 자연수 중 소수인 것을 모두 골라 이들 소수의 합과 최솟값을 찾는 프로그램을 작성하시오.
예를 들어 M=60, N=100인 경우 60이상 100이하의 자연수 중 소수는 61, 67, 71, 73, 79, 83, 89, 97 총 8개가 있으므로, 이들 소수의 합은 620이고, 최솟값은 61이 된다.
입력
입력의 첫째 줄에 M이, 둘째 줄에 N이 주어진다.
M과 N은 10,000이하의 자연수이며, M은 N보다 작거나 같다.
출력
M이상 N이하의 자연수 중 소수인 것을 모두 찾아 첫째 줄에 그 합을, 둘째 줄에 그 중 최솟값을 출력한다.
단, M이상 N이하의 자연수 중 소수가 없을 경우는 첫째 줄에 -1을 출력한다.
예제 입출력
Code
# 입력
M = int(input())
N = int(input())
# 소수 찾기
sum_ = 0
min_ = 10000
for i in range(M, N+1):
count = 0
if i > 1 and i < 4: # i가 2 또는 3인 경우 소수로 판별
sum_ += i
if min_ > i:
min_ = i
else: # 그 외의 숫자인 경우
for j in range(2, i//2 + 1): # 2 ~ i의 절반에 해당하는 숫자까지로 i를 나눠봄
if i % j == 0: # 나누어 떨어지면 더이상 검사하지 않고 다음 숫자 확인
break
else: # 나누어 떨어지지 않는 경우 몇 번 나누어 떨어지지 않았는지 Count
count += 1
if count == i//2 - 1: # 나누어 떨어지지 않은 횟수가 j for문을 돈 횟수와 같다면
sum_ += i # 소수로 판별
if min_ > i:
min_ = i
if sum_ > 0:
print(sum_)
print(min_)
else:
print(-1)
티어 : Silver 4 시간 제한 : 2 초 메모리 제한 : 192 MB 알고리즘 분류 : 수학, 그리디 알고리즘, 정렬
문제
N(1 ≤ N ≤ 100,000)개의 로프가 있다. 이 로프를 이용하여 이런 저런 물체를 들어올릴 수 있다. 각각의 로프는 그 굵기나 길이가 다르기 때문에 들 수 있는 물체의 중량이 서로 다를 수도 있다.
하지만 여러 개의 로프를 병렬로 연결하면 각각의 로프에 걸리는 중량을 나눌 수 있다. k개의 로프를 사용하여 중량이 w인 물체를 들어올릴 때, 각각의 로프에는 모두 고르게 w/k 만큼의 중량이 걸리게 된다.
각 로프들에 대한 정보가 주어졌을 때, 이 로프들을 이용하여 들어올릴 수 있는 물체의 최대 중량을 구해내는 프로그램을 작성하시오. 모든 로프를 사용해야 할 필요는 없으며, 임의로 몇 개의 로프를 골라서 사용해도 된다.
입력
첫째 줄에 정수 N이 주어진다. 다음 N개의 줄에는 각 로프가 버틸 수 있는 최대 중량이 주어진다. 이 값은 10,000을 넘지 않는 자연수이다.
출력
첫째 줄에 답을 출력한다.
예제 입출력
Algorithm
Greedy 이용 1. 각 로프의 중량을 리스트에 담아 sort 2. 1개 쓸 때부터 N개 쓸 때까지의 최댓값 구하기 ☞ 각 최댓값은 [N-i] * i
Code
import sys
input = sys.stdin.readline
# 입력
N = int(input())
weights = []
for _ in range(N):
weights.append(int(input()))
# 중량 리스트 오름차순 정렬
weights.sort()
# 로프 i개 쓸 때부터 N개 쓸 때까지 최댓값 갱신
max_weights = 0
for i in range(1, N+1):
if max_weights < weights[N-i] * i:
max_weights = weights[N-i] * i
print(max_weights)
티어 : Silver 3 시간 제한 : 1 초 메모리 제한 : 256 MB 알고리즘 분류 : 수학, 조합론
문제
1부터 N까지의 수로 이루어진 순열이 있다. 이때, 사전순으로 다음에 오는 순열을 구하는 프로그램을 작성하시오.
사전 순으로 가장 앞서는 순열은 오름차순으로 이루어진 순열이고, 가장 마지막에 오는 순열은 내림차순으로 이루어진 순열이다.
N = 3인 경우에 사전순으로 순열을 나열하면 다음과 같다.
1, 2, 3
1, 3, 2
2, 1, 3
2, 3, 1
3, 1, 2
3, 2, 1
입력
첫째 줄에 N(1 ≤ N ≤ 10,000)이 주어진다. 둘째 줄에 순열이 주어진다.
출력
첫째 줄에 입력으로 주어진 순열의 다음에 오는 순열을 출력한다. 만약, 사전순으로 마지막에 오는 순열인 경우에는 -1을 출력한다.
예제 입출력
Algorithm
Greedy 이용 1. 입력 숫자를 리스트에 받음 2. N이 1이면 -1 출력 3. nums의 마지막 숫자가 N보다 작으면 3.1. 끝에서부터 증가하는 숫자인 경우 모두 pop 3.2. 리스트가 비어있으면 -1 pop 3.3. 리스트가 비어있지 않으면 마지막 값 + 1을 저장해두고 pop후 저장해둔 값 append해서 출력 ☞ 마지막 값 + 1이 N을 넘지 않아야하고 리스트에 들어있지 않은 숫자여야 함 4. nums의 마지막 숫자가 N이면 4.1. 2번 pop 4.2. 마지막 값 + 1을 저장해두고 pop후 저장해둔 값 append해서 출력 ☞ 마지막 값 + 1이 N을 넘지 않아야하고 리스트에 들어있지 않은 숫자여야 함
Code
N = int(input())
nums = list(map(int, input().split()))
# 한자리숫자이면 -1 출력
if N == 1:
print(-1)
# nums의 마지막 숫자가 N보다 작으면 끝에서부터 1씩 증가하는 부분 모두 pop
elif nums[-1] < N:
for index in range(N-1, 0, -1):
if nums[index-1] > nums[index]:
nums.pop()
# nums의 길이가 1인데 값이 N이면 -1출력
if len(nums) == 1 and nums[0] == N:
print(-1)
break
else:
break
nums.pop()
# nums가 빈 리스트가 아니면
if nums:
# 다음에 올 숫자 저장
num = (nums[-1] + 1) % (N + 1)
if num == 0:
num += 1
# 이미 포함되어있는 숫자인지 확인
while num in nums:
if num in nums:
num = (num + 1) % (N+1)
nums.pop()
nums.append(num)
for num in range(1, N+1):
if num not in nums:
nums.append(num)
print(' '.join(list(map(str, nums))))
# nums의 마지막 숫자가 N이면 2번 pop
else:
nums.pop()
num = (nums[-1]+1)%(N+1)
if num == 0:
num += 1
# 이미 포함되어있는 숫자인지 확인
while num in nums:
if num in nums:
num = (num + 1) % (N+1)
nums.pop()
nums.append(num)
# 숫자를 1부터 N까지 확인하면서 들어있지 않은 숫자이면 append
for num in range(1, N+1):
if num not in nums:
nums.append(num)
print(' '.join(list(map(str, nums))))
티어 : Bronze 2 시간 제한 : 1 초 메모리 제한 : 128 MB 알고리즘 분류 : 수학, 구현, 사칙연산
문제
세 개의 자연수 A, B, C가 주어질 때 A × B × C를 계산한 결과에 0부터 9까지 각각의 숫자가 몇 번씩 쓰였는지를 구하는 프로그램을 작성하시오.
예를 들어 A = 150, B = 266, C = 427 이라면 A × B × C = 150 × 266 × 427 = 17037300 이 되고, 계산한 결과 17037300 에는 0이 3번, 1이 1번, 3이 2번, 7이 2번 쓰였다.
입력
첫째 줄에 A, 둘째 줄에 B, 셋째 줄에 C가 주어진다. A, B, C는 모두 100보다 크거나 같고, 1,000보다 작은 자연수이다.
출력
첫째 줄에는 A × B × C의 결과에 0 이 몇 번 쓰였는지 출력한다. 마찬가지로 둘째 줄부터 열 번째 줄까지 A × B × C의 결과에 1부터 9까지의 숫자가 각각 몇 번 쓰였는지 차례로 한 줄에 하나씩 출력한다.
예제 입출력
Code
A = int(input())
B = int(input())
C = int(input())
num = str(A*B*C)
count = [0 for _ in range(10)]
for i in range(len(num)):
count[int(num[i])] += 1
for i in count:
print(i)
티어 : Silver 2 시간 제한 : 2 초 메모리 제한 : 128 MB 알고리즘 분류 : 그리디 알고리즘, 정렬
문제
한 개의 회의실이 있는데 이를 사용하고자 하는 N개의 회의에 대하여 회의실 사용표를 만들려고 한다. 각 회의 I에 대해 시작시간과 끝나는 시간이 주어져 있고, 각 회의가 겹치지 않게 하면서 회의실을 사용할 수 있는 회의의 최대 개수를 찾아보자. 단, 회의는 한번 시작하면 중간에 중단될 수 없으며 한 회의가 끝나는 것과 동시에 다음 회의가 시작될 수 있다. 회의의 시작시간과 끝나는 시간이 같을 수도 있다. 이 경우에는 시작하자마자 끝나는 것으로 생각하면 된다.
입력
첫째 줄에 회의의 수 N(1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N+1 줄까지 각 회의의 정보가 주어지는데 이것은 공백을 사이에 두고 회의의 시작시간과 끝나는 시간이 주어진다. 시작 시간과 끝나는 시간은
보다 작거나 같은 자연수 또는 0이다.
출력
첫째 줄에 최대 사용할 수 있는 회의의 최대 개수를 출력한다.
예제 입출력
힌트
(1,4), (5,7), (8,11), (12,14) 를 이용할 수 있다.
Algorithm
Greedy 1. 리스트로 입력받아 끝나는 시간을 기준으로 오름차순 정렬 2. stack에 첫 번째 회의 추가 3. stack의 마지막 회의의 끝나는 시간보다 시작 시간이 크거나 같은 회의만 추가 4. stack의 길이 출력
Code
import sys
input = sys.stdin.readline
# 입력
N = int(input())
I = []
for _ in range(N):
I.append(tuple(map(int, input().split())))
# 시작 시간, 회의 시간 순서대로 기준을 잡아 정렬
I.sort(key = lambda x: (x[1], x[0]))
# 회의 시작 시간이 이전 회의 끝나는 시간보다 크거나 같으면 추가
stack = [I[0]]
for index in range(1, N):
if I[index][0] >= stack[-1][1]:
stack.append(I[index])
print(len(stack))
티어 : Silver 2 시간 제한 : 1 초 메모리 제한 : 256 MB 알고리즘 분류 : 브루트포스 알고리즘, 백트래킹
문제
두 종류의 부등호 기호 ‘<’와 ‘>’가 k개 나열된 순서열 A가 있다. 우리는 이 부등호 기호 앞뒤에 서로 다른 한 자릿수 숫자를 넣어서 모든 부등호 관계를 만족시키려고 한다. 예를 들어, 제시된 부등호 순서열 A가 다음과 같다고 하자.
A ⇒ < < < > < < > < >
부등호 기호 앞뒤에 넣을 수 있는 숫자는 0부터 9까지의 정수이며 선택된 숫자는 모두 달라야 한다. 아래는 부등호 순서열 A를 만족시키는 한 예이다.
3 < 4 < 5 < 6 > 1 < 2 < 8 > 7 < 9 > 0
이 상황에서 부등호 기호를 제거한 뒤, 숫자를 모두 붙이면 하나의 수를 만들 수 있는데 이 수를 주어진 부등호 관계를 만족시키는 정수라고 한다. 그런데 주어진 부등호 관계를 만족하는 정수는 하나 이상 존재한다. 예를 들어 3456128790 뿐만 아니라 5689023174도 아래와 같이 부등호 관계 A를 만족시킨다.
5 < 6 < 8 < 9 > 0 < 2 < 3 > 1 < 7 > 4
여러분은 제시된 k개의 부등호 순서를 만족하는 (k+1)자리의 정수 중에서 최댓값과 최솟값을 찾아야 한다. 앞서 설명한 대로 각 부등호의 앞뒤에 들어가는 숫자는 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }중에서 선택해야 하며선택된 숫자는 모두 달라야 한다.
입력
첫 줄에 부등호 문자의 개수를 나타내는 정수 k가 주어진다. 그 다음 줄에는 k개의 부등호 기호가 하나의 공백을 두고 한 줄에 모두 제시된다. k의 범위는 2 ≤ k ≤ 9 이다.
출력
여러분은 제시된 부등호 관계를 만족하는 k+1 자리의 최대, 최소 정수를 첫째 줄과 둘째 줄에 각각 출력해야 한다. 단 아래 예(1)과 같이 첫 자리가 0인 경우도 정수에 포함되어야 한다. 모든 입력에 답은 항상 존재하며 출력 정수는 하나의 문자열이 되도록 해야 한다.
예제 입출력
Algorithm
back tracking - 재귀 1. 0부터 9까지 stack에 추가 1.1. stack이 비어있으면 바로 append 1.2. stack이 비어있지 않으면 stack이 없는 값이며 부등호를 확인해 < 이면 stack[-1]보다 큰 값, > 이면 stack[-1]보다 작은 값만 추가 2. 재귀함수 호출 3. 재귀함수 return되면 pop 4. stack의 길이가 K+1이 되면 최댓값, 최솟값 갱신
Code
def back_tracking():
global min_
global max_
# stack의 길이가 k+1이 되면
if len(stack) == k+1:
num = int(''.join(list(map(str, stack))))
# 최솟값 갱신
if min_ > num:
min_ = num
# 최댓값 갱신
if max_ < num:
max_ = num
else:
for i in range(10):
# stack 비어있으면 바로 추가
if not stack:
stack.append(i)
back_tracking()
stack.pop()
# stack 비어있지 않으면
elif i not in stack:
if inequalities[len(stack)-1] == '<' and stack[-1] < i:
# stack[-1]보다 큰 값만 추가
stack.append(i)
back_tracking()
stack.pop()
elif inequalities[len(stack)-1] == '>' and stack[-1] > i:
# stack[-1]보다 작은 값만 추가
stack.append(i)
back_tracking()
stack.pop()
import sys
input = sys.stdin.readline
k = int(input())
inequalities = list(input().rstrip().split())
global min_
global max_
min_ = 9876543211
max_ = 0
stack = []
back_tracking()
answer = ''
for i in range(k+1 - len(str(max_))):
answer += '0'
answer += str(max_) + '\n'
for i in range(k+1 - len(str(min_))):
answer += '0'
answer += str(min_)
print(answer)
티어 : Silver 1 시간 제한 : 2 초 메모리 제한 : 512 MB 알고리즘 분류 : 브루트포스 알고리즘
문제
오늘은 스타트링크에 다니는 사람들이 모여서 축구를 해보려고 한다. 축구는 평일 오후에 하고 의무 참석도 아니다. 축구를 하기 위해 모인 사람은 총 N명이다. 이제 스타트 팀과 링크 팀으로 사람들을 나눠야 한다. 두 팀의 인원수는 같지 않아도 되지만, 한 명 이상이어야 한다.
BOJ를 운영하는 회사 답게 사람에게 번호를 1부터 N까지로 배정했고, 아래와 같은 능력치를 조사했다. 능력치 Sij는 i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치이다. 팀의 능력치는 팀에 속한 모든 쌍의 능력치 Sij의 합이다. Sij는 Sji와 다를 수도 있으며, i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치는 Sij와 Sji이다.
N=4이고, S가 아래와 같은 경우를 살펴보자.
예를 들어, 1, 2번이 스타트 팀, 3, 4번이 링크 팀에 속한 경우에 두 팀의 능력치는 아래와 같다.
스타트 팀: S12+ S21= 1 + 4 = 5
링크 팀: S34+ S43= 2 + 5 = 7
1, 3번이 스타트 팀, 2, 4번이 링크 팀에 속하면, 두 팀의 능력치는 아래와 같다.
스타트 팀: S13+ S31= 2 + 7 = 9
링크 팀: S24+ S42= 6 + 4 = 10
축구를 재미있게 하기 위해서 스타트 팀의 능력치와 링크 팀의 능력치의 차이를 최소로 하려고 한다. 위의 예제와 같은 경우에는 1, 4번이 스타트 팀, 2, 3번 팀이 링크 팀에 속하면 스타트 팀의 능력치는 6, 링크 팀의 능력치는 6이 되어서 차이가 0이 되고 이 값이 최소이다.
입력
첫째 줄에 N(4 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에 S가 주어진다. 각 줄은 N개의 수로 이루어져 있고, i번 줄의 j번째 수는 Sij이다. Sii는 항상 0이고, 나머지 Sij는 1보다 크거나 같고, 100보다 작거나 같은 정수이다.
출력
첫째 줄에 스타트 팀과 링크 팀의 능력치의 차이의 최솟값을 출력한다.
예제 입출력
Algorithm
back tracking - 재귀 1. start에 숫자 추가 1.1. start가 비어있으면 그냥 추가 1.2. start가 비어있지 않으면 stack에 들어있지 않고 stack의 마지막 숫자보다 큰 숫자만 추가 2. append될 때마다 두 팀의 능력치 차이에 따라 answer 갱신 3. 재귀함수 호출 4. 재귀함수 return되면 pop 5. start의 길이가 N-1이 되면 append하기 전에 pop부터 하도록 구현
Code
import sys
input = sys.stdin.readline
def back_tracking(s_start, s_link):
global answer
# start 길이가 N - 1이 되면 append하기 전에 pop부터 하도록 구현
if len(start) == N-1:
pass
else:
for num in range(N):
# start 비어 있으면 숫자 추가
if not start:
# start의 첫 번째 원소가 1이면 return
if num == 1:
return answer
start.append(num)
# start에 값이 추가될 때마다 능력치 확인
for i in start[:-1]:
s_start += (S[i][num] + S[num][i])
for i in range(N):
if i not in start:
s_link -= (S[num][i] + S[i][num])
# answer값 갱신
if answer < max(s_start - s_link, s_link - s_start):
answer = max(s_start - s_link, s_link - s_start)
# 재귀함수 호출하고 return되면 pop
back_tracking(s_start, s_link)
for i in start[:-1]:
s_start -= S[i][start[-1]] + S[start[-1]][i]
for i in range(N):
if i not in start:
s_link += (S[num][i] + S[i][num])
start.pop()
# start 비어있지 않으면 start에 들어있지 않고 start의 마지막 숫자보다 큰 값만 추가
elif num not in start and start[-1] < num:
start.append(num)
for i in start[:-1]:
s_start += S[i][num] + S[num][i]
for i in range(N):
if i not in start:
s_link -= (S[num][i] + S[i][num])
# answer값 갱신
if answer > max(s_start - s_link, s_link - s_start):
answer = max(s_start - s_link, s_link - s_start)
# 재귀함수 호출하고 return되면 pop
back_tracking(s_start, s_link)
for i in start[:-1]:
s_start -= S[i][num] + S[num][i]
for i in range(N):
if i not in start:
s_link += (S[num][i] + S[i][num])
start.pop()
N = int(input())
S = []
temp = []
s_link = 0
for _ in range(N):
temp = list(map(int, input().split()))
S.append(temp)
s_link += sum(temp)
start = []
global answer
answer = 100*N*N
s_start = 0
print(back_tracking(s_start, s_link))