실습_2. 문제해결절차, 완전탐색, 시간복잡도
Updated:
실습
연속 부분 최대합
n개의 숫자가 주어질 때, 연속 부분을 선택하여 그 합을 최대화 하는 프로그램을 작성하시오. 예를 들어, 다음과 같이 8개의 숫자가 있다고 하자.
1 2 -4 5 3 -2 9 -10
이 때, 연속 부분이란 연속하여 숫자를 선택하는 것을 말한다. 가능한 연속 부분으로써 [1, 2, -4], [5, 3, -2, 9], [9, -10] 등이 있을 수 있다. 이 연속 부분들 중에서 가장 합이 큰 연속 부분은 [5, 3, -2, 9] 이며, 이보다 더 합을 크게 할 수는 없다. 따라서 연속 부분 최대합은 5+3+(-2)+9 = 15 이다.
- 입력 예시
1 2 -4 5 3 -2 9 -10
- 출력 예시
15
- 문제 조건
입력되는 수의 개수는 최대 100개입니다.
import sys
def getSubsum(data) :
'''
n개의 숫자가 list로 주어질 때, 그 연속 부분 최대합을 반환하는 함수를 작성하세요.
'''
sum = 0
maxs = 0
for i in range(1,len(data)+1):
#print(i)
for j in range(0, len(data) - i + 1):
#print(" ",j)
for k in range(j,j+i):
sum+=data[k]
maxs = max(sum,maxs)
sum = 0
return maxs
def main():
'''
이 부분은 수정하지 마세요.
'''
data = [int(x) for x in input().split()]
print(getSubsum(data))
if __name__ == "__main__":
main()
멱집합 구하기
집합 A에 다하여, A의 모든 부분집합을 원소로 가지는 집합을 A의 멱집합이라고 한다. 예를 들어, 집합 A의 원소가 {1, 2, 3} 일 경우, A의 멱집합은 다음과 같이 8개의 원소를 갖는 집합이다.
{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}
집합 A의 원소는 1부터 nn까지의 자연수로 구성된다. nn이 주어질 때, A의 멱집합의 원소를 사전 순서대로 모두 출력하는 프로그램을 작성하시오. 단, 공집합은 제외하고 출력한다.
- 입력 예시
3
- 출력 예시
1
1 2
1 2 3
1 3
2
2 3
3
- 문제 조건
원소의 개수는 10개를 넘지 않습니다.
공집합은 출력하지 않습니다.
import sys
def powerSet(n) :
'''
n개의 원소를 가지는 집합 A의 멱집합의 원소를 사전 순서대로 list로 반환하는 함수를 작성하시오.
예를 들어, n = 3 일 경우 다음의 list를 반환한다.
[ [1], [1, 2], [1, 3], [1, 2, 3], [2], [2, 3], [3] ]
'''
def ham(k, n):
if k == n:
return [[k]]
re = ham(k+1,n)
arr = [[k]]
for i in range(len(re)):
arr += [[k]+re[i]]
arr += re
print(arr)
return arr
return ham(1,n)
def main():
'''
이 부분은 수정하지 마세요.
'''
n = int(input())
result = powerSet(n)
for line in result :
print(*line)
if __name__ == "__main__":
main()
균형 맞추기
nn개의 숫자가 주어진다. 이제 이 숫자를 두 개의 그룹으로 나눌 것이다. 예를 들어 5개의 숫자 [1, -3, 4, 5, -2] 가 주어진다면, 이를 두 개의 그룹으로 나누는 경우는 여러가지가 있을 수 있다. 가능한 경우로써 [1, -3], [4, 5, -2] 가 있을 수 있고, 또 다른 경우로는 [1, 4, -2], [-3, 5] 가 있을 수 있다.
나눈 두 그룹을 A, B라고 할 때, (A의 원소의 합) - (B의 원소의 합) 의 절댓값을 최소화 하는 프로그램을 작성하시오. 위의 예제에서는 A = [1, 4, -2], B = [-3, 5] 라고 하였을 때 (A의 원소의 합) - (B의 원소의 합) 의 절댓값 = | 3 - 2 | = 1 이며, 이보다 더 작은 값을 만드는 A, B는 존재하지 않는다. |
이 경우 절댓값의 최솟값인 1을 출력하면 된다.
- 입력 예시
1 -3 4 5 -2
- 출력 예시
1
- 문제 조건
입력되는 수는 최대 20개를 넘지 않는다.
import sys
def makeEqual(data) :
'''
n개의 숫자를 두 그룹 A, B로 나눈다고 할 때,
| (A의 원소의 합) - (B의 원소의 합) | 의 최솟값을 반환하는 함수를 작성하시오.
'''
print(data)
check = [False for i in range(len(data))]
mins = [987654321]
def ham(check, cnt):
if cnt == len(check):
#print(check)
t_sum = 0
f_sum = 0
for i in range(len(check)):
if check[i]:
t_sum+=data[i]
else:
f_sum+=data[i]
mins[0] = min(mins[0],abs(t_sum - f_sum))
return
check[cnt] = True
ham(check,cnt+1)
check[cnt] = False
ham(check,cnt+1)
ham(check,0)
print(mins[0])
return mins[0]
def main():
'''
이 부분은 수정하지 마세요.
'''
data = [int(x) for x in input().split()]
print(makeEqual(data))
if __name__ == "__main__":
main()
미션
각 자릿수의 차이
두 자연수가 주어질 때, 각 자릿수의 숫자를 비교하여 다른 개수를 세는 프로그램을 작성하시오.
예를 들어, 두 자연수가 각각 212, 233 이라면 10의 자리와 1의 자리가 다르므로, 총 2개의 자리가 다르다.
- 입력 예시 1
212
233
- 출력 예시 1
2
- 입력 예시 2
123
123456
- 출력 예시 2
6
def diffDigit(a, b) :
'''
a, b의 서로 다른 자리수의 개수를 반환한다
'''
a_cnt = 0
b_cnt = 0
cnt = 0
while a!=0 or b!=0:
print(a,b)
if a%10 != b %10 and a!=0 and b!= 0:
cnt +=1
if a!= 0:
a_cnt+=1
if b!=0:
b_cnt+=1
a//=10
b//=10
return cnt + abs(a_cnt - b_cnt);
def main():
'''
Do not change this code
'''
a = int(input())
b = int(input())
print(diffDigit(a, b))
if __name__ == "__main__":
main()
기울기가 가장 큰 두 점 찾기
2차원 평면에 nn개의 점이 있다. 이 점들 중에서 두 점을 선택했을 때, 그 기울기의 절댓값의 최댓값을 출력하는 프로그램을 작성하시오. 단, 모든 점의 x좌표는 다르다고 가정한다. 또한, 두 점 (x1, y1), (x2, y2)의 기울기는 (y2 - y1) / (x2 - x1) 으로 정의된다.
예를 들어, 4개의 점이 각각 (0, 3), (1, 1), (2, 2), (4, 1) 에 위치해 있다고 하면, 기울기의 절댓값의 최댓값은 2가 된다.
이 경우 기울기 절댓값의 최댓값인 2를 출력합니다.
입력으로는 첫줄에 점의 개수가, 그 다음줄부터는 점의 xx좌표와 yy좌표가 입력됩니다.
- 입력 예시
4
0 3
1 1
2 2
4 1
- 출력 예시
2.000
- 문제 조건
점의 개수는 최대 100개를 넘지 않습니다.
점의 좌표는 모두 정수입니다.
출력은 소숫점 넷째자리에서 반올림하여 출력합니다.
import sys
def maxSlope(points) :
'''
n개의 점들 중에서 2개의 점을 선택했을 때, 얻을 수 있는 기울기의 절댓값 중에서 가장 큰 값을 반환하는 함수를 작성하세요.
**주의** : 소숫점 넷째자리에서 반올림하는 것은 고려할 필요가 없습니다. 이는 main()에서 출력을 할 때에 처리가 되므로, 기울기의 최댓값을 구하는 것에 집중해 주시길 바랍니다.
'''
print(points)
maxs = 0
for i in range(len(points)-1):
for j in range(i+1,len(points)):
maxs = max(maxs,abs((points[i][1] - points[j][1])/(points[i][0] - points[j][0])))
return maxs
def main():
'''
이 부분은 수정하지 마세요.
'''
n = int(input())
points = []
for i in range(n) :
line = [int(x) for x in input().split()]
points.append( (line[0], line[1]) )
print("%.3lf" % maxSlope(points))
if __name__ == "__main__":
main()
가장 가까운 두 점 찾기
2차원 평면에 nn개의 점이 있다. 이 점들 중에서 그 거리가 가장 가까운 두 점 사이의 거리의 제곱을 출력하는 프로그램을 작성하시오. 단, 두 점 (x1, y1)과 (x2, y2) 사이의 거리는 sqrt( (x1-x2)^2 + (y1-y2)^2 ) 로 정의된다.
예를 들어, 4개의 점이 각각 (0, 3), (1, 1), (2, 2), (7, 1) 에 위치해 있다고 하면, 가장 가까운 두 점은 (1, 1)과 (2, 2)이며, 그 거리의 제곱은 2이다.
이때 그 거리의 제곱인 2를 출력하면 됩니다.
- 입력 예시
4
0 3
1 1
2 2
7 1
- 출력 예시
2
- 문제 조건
점의 개수는 최대 100개를 넘지 않습니다.
점의 좌표는 모두 정수입니다.
import sys
def getDist(points) :
'''
n개의 점이 주어질 때, 가장 가까운 두 점 사이의 거리의 제곱을 반환하는 함수를 작성하세요.
예를 들어, 점이 4개가 있고, 각각의 좌표가 (0, 3), (1, 1), (2, 2), (7, 1) 이라면 points에는 다음과 같이 그 정보가 저장됩니다.
points = [ (0, 3), (1, 1), (2, 2), (7, 1) ]
이 때, 가장 가까운 두 점 사이의 거리의 제곱은 2입니다.
'''
print()
mins = 987654321
for i in range(len(points)-1):
for j in range(i+1,len(points)):
print(i,j)
mins = min(mins,(points[i][0] - points[j][0])**2+(points[i][1] - points[j][1])**2)
return mins
def main():
'''
이 부분은 수정하지 마세요.
'''
n = int(input())
points = []
for i in range(n) :
line = [int(x) for x in input().split()]
points.append( (line[0], line[1]) )
print(getDist(points))
if __name__ == "__main__":
main()
N-Queen
nn x nn 의 체스 판에 n개의 Queen을 놓으려 합니다. 이 때, 다음의 규칙을 반드시 따라야 합니다.
같은 행에 2개 이상의 Queen이 존재해서는 안됩니다. 같은 열에 2개 이상의 Queen이 존재해서는 안됩니다. 하나의 대각선에 2개 이상의 Queen이 존재해서는 안됩니다. 이는 ‘\‘ 방향의 대각선과 ‘/‘ 방향의 대각선 모두에 대하여 해당되는 조건입니다.
- 입력 예시 1
4
- 출력 예시 1
2
- 입력 예시 2
5
- 출력 예시 2
10
- 문제 조건
퀸의 개수는 최대 10개입니다.
import sys
sys.setrecursionlimit(100000)
dr = [-1,-1,1,1]
dc = [-1,1,-1,1]
cnt = 0
def set_q(n,row,check,q_map):
if row == n:
global cnt
cnt += 1
for i in range(n):
if check[i]:
continue
che = False
for j in range(4):
tmp_r = row
tmp_c = i
while True:
tmp_r+=dr[j]
tmp_c+=dc[j]
if tmp_r<0 or tmp_r>=n or tmp_c<0 or tmp_c>=n:
break
if q_map[tmp_r][tmp_c] == 1:
che = True
break
if che:
break
if che:
continue
q_map[row][i] = 1
check[i] = True
set_q(n,row + 1,check,q_map)
q_map[row][i] = 0
check[i] = False
def nQueen(n) :
'''
n개의 Queen을 배치하는 경우의 수를 반환하는 함수를 작성하세요.
'''
q_map = [[0 for j in range(n)] for i in range(n)]
check = [False for i in range(n)]
set_q(n,0,check,q_map)
global cnt
tmp = cnt
cnt = 0
return tmp
def main():
'''
이 부분은 수정하지 마세요.
'''
n = int(input())
print(nQueen(n))
cnt = 0
if __name__ == "__main__":
main()
뒤집기
다음과 같이 nn x mm 의 판이 주어집니다. () 각각의 판에는 흰색 혹은 검은색이 칠해져 있으며, 흰색은 0, 그리고 검은색은 1로 주어진다.
이제 이 모든 판의 색깔을 흰색으로 만들려고 한다. 색을 바꾸는 것은 특정 칸을 ‘클릭’ 함으로써 이루어진다. 한 번에 한 칸을 ‘클릭’ 할 수 있으며, 한 칸을 ‘클릭’ 할 경우에는 그 칸의 색깔 뿐만 아니라 상, 하, 좌, 우의 모든 색깔이 바뀐다. 즉, 흰색일 경우에는 검은색으로, 검은색일 경우에는 흰색으로 바뀐다. 만약 (0, 0) 과 같이 상, 하, 좌, 우 중에서 몇몇 칸만 존재할 경우, 그 존재하는 칸의 색깔만 바뀌게 된다.
nn x mm 의 판의 상태가 주어질 때, 이를 모두 흰색으로 만들기 위하여 ‘클릭’ 해야하는 최소 칸의 수를 출력하는 프로그램을 작성하시오. 만약, ‘클릭’을 통하여 모두 흰색으로 바꾸는 것이 불가능하다면 -1을 출력한다.
-
입력 첫째 줄에 nn, mm이 주어진다. 두 번째 줄부터 각 칸의 상태가 주어진다. 0은 흰색을 의미하며, 1은 검은색을 의미한다.
-
입력 예시 1
4 3
0 1 0
1 0 1
1 0 1
0 1 0
- 출력 예시 1
2
-
설명 1 (2, 1)을 클릭한 후, (1, 1)을 클릭하면 모든 칸이 흰색이 된다.
-
입력 예시 2
4 6
0 1 1 0 1 0
1 1 0 0 1 1
1 0 0 0 1 0
0 1 0 0 0 0
- 출력 예시 2
4
- 설명 2
(1, 2), (2, 1), (1, 4), 그리고 (1, 1)을 차례대로 클릭하면 모든 칸을 흰색으로 만들 수 있다.
- 입력 예시 3
4 4
0 0 0 0
0 0 1 1
0 0 1 0
0 0 0 0
- 출력 예시 3
-1
-
문제 조건
- 10001≤n≤1000
- 101≤m≤10
import sys
import copy
sys.setrecursionlimit(100000)
dr = [0,-1,1,0,0]
dc = [0,0,0,-1,1]
mins = 987654321
def cal(check,n,m,myMap):
tmp_arr = copy.deepcopy(myMap)
cnt = 0
global mins
for j in range(m):
if check[j]:
cnt+=1
if cnt >=mins:
return
for k in range(5):
i_tmp = 0
j_tmp = j
if i_tmp+dr[k]<0 or i_tmp+dr[k]>=n or j_tmp+dc[k]<0 or j_tmp+dc[k]>=m:
continue
tmp_arr[i_tmp+dr[k]][j_tmp+dc[k]] = (tmp_arr[i_tmp+dr[k]][j_tmp+dc[k]]+1)%2
############ 출력
# for i in range(n):
# for j in range(m):
# print(tmp_arr[i][j],end=' ')
# print()
########### 구현
for i in range(1,n):
for j in range(m):
if tmp_arr[i-1][j] == 1:
cnt += 1
if cnt >= mins:
return
for k in range(5):
i_tmp = i
j_tmp = j
if i_tmp+dr[k]<0 or i_tmp+dr[k]>=n or j_tmp+dc[k]<0 or j_tmp+dc[k]>=m:
continue
tmp_arr[i_tmp+dr[k]][j_tmp+dc[k]] = (tmp_arr[i_tmp+dr[k]][j_tmp+dc[k]]+1)%2
che = True
############ 출력
# print()
# for i in range(n):
# for j in range(m):
# print(tmp_arr[i][j],end=' ')
# print()
for i in range(n):
for j in range(m):
if tmp_arr[i][j] == 1:
return
mins = min(mins, cnt)
def ham(cnt,n,m,check,myMap):
if cnt == m:
cal(check,n,m,myMap)
return
check[cnt] = False
ham(cnt+1,n,m,check,myMap)
check[cnt] = True
ham(cnt+1,n,m,check,myMap)
def flip(myMap, n, m) :
'''
모든 칸을 흰색으로 바꾸기 위해 최소로 클릭해야 하는 횟수를 반환하는 함수를 작성하세요.
'''
check = [False for i in range(m)]
ham(0,n,m,check,myMap)
global mins
tmp = mins
mins = 987654321
if tmp == 987654321:
tmp = -1
return tmp
def main():
'''
이 부분은 수정하지 마세요.
'''
data = [int(x) for x in input().split()]
n = data[0]
m = data[1]
myMap = []
for i in range(n) :
line = [int(x) for x in input().split()]
myMap.append(line)
print(flip(myMap, n, m))
if __name__ == "__main__":
main()
Leave a comment