728x90
반응형

정렬Sorting

이란 데이터를 특정한 기준에 따라서 순서대로 나열하는 것을 말한다. 정렬을 이용해서 이진탐색도 가능해지는 것이다.

 

선택 정렬(Selection Sort) 

: 가장 먼저 생각이 날 수 있는 자연스러운 정렬 알고리즘

  각 위치에 어떤 값이 들어갈지 찾는다.

 

가장 작은 값을 찾아서 0번 인덱스에 놓고, 두 번째로 작은 값을 찾아서 1번 인덱스에 놓고, 세 번째로 작은 값을 찾아서 2번 인덱스에 놓고.....

즉, 데이터가 무작위로 여러 개 있을 때, 이중에서 가장 작은 데이터를 맨 앞에 있는 데이터와 바꾸고, 그 다음 작은 데이터를 앞에서 2번째 데이터와 바꾸는 과정을 반복하자.

array = [2,4,5,1,3,9,7,8]

for i in range(len(array)):
    min_index=i
    for j in range(i+1,len(array)):
        if array[min_index]>array[j]:
            min_index=j
    array[i],array[min_index]=array[min_index],array[i]

print(array)

선택 정렬의 시간 복잡도는 N-1번 만큼 가장 작은 수를 찾아서 맨 앞으로 보내야 한다. 또한 매번 가장 작은 수를 찾기 위해서 비교 연산이 필요하다. 연산 횟수는 N+(N-1)+(N-2) ... 이렇기 때문에 O(N^2)시간복잡도가 나온다.


삽입 정렬(Insertion Sort)

: 각 값이 어떤 위치에 들어갈지 찾는다

 

정렬 문제의 경우 "절대적인 좋은 답"이란 없다. 상황에 따른 각 알고리즘의 장단점을 파악해야 올바른 알고리즘을 선택할 수 있다. 

삽입 정렬은 선택 정렬처럼 동작 원리를 직관적으로 이해하기 쉽다. 삽입 정렬은 필요할 때만 위치를 바꾸므로 '데이터가 거의 정렬되어 있을 때' 훨씬 효율적이다. 선택 정렬은 현재 데이터의 상태와 상관없이 무조건 모든 원소를 비교하고 위치를 바꾸는 반면 삽입 정렬은 그렇지 않다. 

 

삽입 정렬은 특정한 데이터가 적절한 위치에 들어가기 이전에, 그 앞까지의 데이터는 이미 정렬되어 있다고 가정한다. 정렬되어 있는 데이터 리스트에서 적절한 위치를 찾은 뒤에, 그 위치에 삽입된다.

array = [7,5,9,0,3,1,2,8,6]

for i in range(1,len(array)):
    for j in range(i,0,-1):#인덱스 i부터 1까지 감소하며 반복하는 문법
        if array[j]<array[j-1]:
            array[j],array[j-1]=array[j-1],array[j]
        else:
            break
print(array)

 

삽입 정렬의 시간복잡도는 O(N^2)이다. 그러나 최선의 경우 O(N)의 시간 복잡도를 가진다. 모두 정렬되어있으면 O(N)의 시간복잡도를 가진다.


합병 정렬(Merge Sort)

 Divide and Conquer에서 대표적으로 설명하는 정렬 방식이다.

 Divide에서는 리스트를 왼쪽 반, 오른쪽 반으로 나눈다. 왼쪽 반을 정렬하는 부분 문제랑 오른쪽 반을 정렬하는 부분 문제로 나누어 주는 것이다.

 Conquer 단계에서는 왼쪽 리스트와 오른쪽 리스트를 각각 정렬해 준다.

 Combine 단계에서는 정렬된 두 리스트를 하나의 정렬된 리스트로 합병한다.

 

두 리스트를 하나로 Combine 할 때가 중요하다. 이미 정렬되었다고 가정하였을때 왼쪽이 제일 작게 정렬했다고 생각하자. 그럼 왼쪽과 오른쪽의 첫번째 값을 비교해 주어서 더 작은 것을 Combined된 리스트에 넣어준다.

 계속 하나씩 작은것부터 차례대로 넣어주면 한쪽 리스트만 남을거이다. 이것은 이미 정렬되어 있는 것이기 때문에 남은 것을 왼쪽부터 넣으면 된다. 이렇게 하면 하나의 정렬된 리스트가 된다.

 

def merge(list1, list2):
    i = 0
    j = 0

    # 정렬된 항목들을 담을 리스트
    merged_list = []

    # list1과 list2를 돌면서 merged_list에 항목 정렬
    while i < len(list1) and j < len(list2):
        if list1[i] > list2[j]:
            merged_list.append(list2[j])
            j += 1
        else:
            merged_list.append(list1[i])
            i += 1

    # list2에 남은 항목이 있으면 정렬 리스트에 추가
    if i == len(list1):
        merged_list += list2[j:]

    # list1에 남은 항목이 있으면 정렬 리스트에 추가
    elif j == len(list2):
        merged_list += list1[i:]

    return merged_list

# 테스트
print(merge([1],[]))
print(merge([],[1]))
print(merge([2],[1]))
print(merge([1, 2, 3, 4],[5, 6, 7, 8]))
print(merge([5, 6, 7, 8],[1, 2, 3, 4]))
print(merge([4, 7, 8, 9],[1, 3, 6, 10]))
[1]
[1]
[1, 2]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 3, 4, 6, 7, 8, 9, 10]

 

결론적으로 합병 정렬을 재귀적으로 구하면 다음과 같다.

def merge(list1, list2):
    merged_list=[]
    index1=0
    index2=0
    while index1<len(list1) and index2<len(list2):
        if list1[index1]<list2[index2]:
            merged_list.append(list1[index1])
            index1+=1
        else:
            merged_list.append(list2[index2])
            index2+=1
    merged_list=merged_list+list1[index1:]+list2[index2:]
    return merged_list
# 합병 정렬
def merge_sort(my_list):
    return merge(merge_sort(my_list[:len(my_list)//2]),merge_sort(my_list[len(my_list)//2:]))
# 테스트
print(merge_sort([1, 3, 5, 7, 9, 11, 13, 11]))
print(merge_sort([28, 13, 9, 30, 1, 48, 5, 7, 15]))
print(merge_sort([2, 5, 6, 7, 1, 2, 4, 7, 10, 11, 4, 15, 13, 1, 6, 4]))

퀵 정렬 (Quick Sort)

Divide and Conquer를 사용하는 또다른 정렬방법은 퀵 정렬(Quicksort)이다. 합병 정렬은 사실 Divide랑 Conquer단계는 생각하기 쉬우나 Combine이 어렵다. 퀵 정렬은 완전히 반대로 Divide과정이 되게 어렵다. 


 

1. Divide 

 

Partition에는 2단계가 있다. 먼저 pivot을 정해주는 것이다. 두 번째 단계는 이 pivot을 기준으로 값들을 새롭게 배치하는 것이다. pivot을 기준으로 더 작은 값들은 왼쪽으로, 더 큰 값들은 오른쪽으로 오게 하는 것이다. 

 

2. Conquer 

 

pivot 왼쪽과 pivot 오른쪽을 정렬해 준다. 그리고 왼쪽과 오른쪽을 재귀적으로 sort해주면 된다.

 

3. Combine

 

할 일이 없다


 

Divide 부분을 다시 한 번 살펴보자. 일단 partition함수는 parameter를 3개 받는다.

def partition(my_list,start,end):

 

 

 

변수를 3개 두어야 된다. start, big_index, i, pivot. start는 처음 인덱스, b는 pivot값보다 큰 인덱스, i는 계속 진행해가는 인덱스이다. 

 

아래는 Divide과정인 Partition 하는 과정을 담고 있다.

 

# 두 요소의 위치를 바꿔주는 helper function
def swap_elements(my_list, index1, index2):
    # 코드를 작성하세요.
    my_list[index1],my_list[index2]=my_list[index2],my_list[index1]

# 퀵 정렬에서 사용되는 partition 함수
def partition(my_list, start, end):
    # 코드를 작성하세요.
    pivot = end
    big_index=0
    for i in range(len(my_list)-1):
        if my_list[i]>my_list[pivot]:
            continue
        else:
            swap_elements(my_list,i,big_index)
            big_index+=1
    swap_elements(my_list,pivot,big_index)
    pivot=big_index
    return pivot

# 테스트 1
list1 = [4, 3, 6, 2, 7, 1, 5]
pivot_index1 = partition(list1, 0, len(list1) - 1)
print(list1)
print(pivot_index1)

# 테스트 2
list2 = [6, 1, 2, 6, 3, 5, 4]
pivot_index2 = partition(list2, 0, len(list2) - 1)
print(list2)
print(pivot_index2)

 

partition을 했으면 merge_sort처럼 나머지를 재귀함수를 통해서 구하면 된다.

# 두 요소의 위치를 바꿔주는 helper function
def swap_elements(my_list, index1, index2):
    my_list[index1], my_list[index2] = my_list[index2], my_list[index1]
# 퀵 정렬에서 사용되는 partition 함수
def partition(my_list, start, end):
    i = start
    pivot = end
    big_index = start
    while i < pivot:
        if my_list[i] <= my_list[pivot]:
            swap_elements(my_list, i, big_index)
            big_index += 1
        i += 1
    swap_elements(my_list, big_index, pivot)
    pivot = big_index
    return pivot
# 퀵 정렬 (start, end 파라미터 없이도 호출이 가능하도록 수정해보세요!)
def quicksort(my_list,start=0,end=None):
    if end==None:
        end=len(my_list)-1
    if end-start<1:
        return
    pivot = partition(my_list, start, end)
    quicksort(my_list,start,pivot-1)
    quicksort(my_list,pivot+1,end)
# 테스트 1
list1 = [1, 3, 5, 7, 9, 11, 13, 11]
quicksort(list1) # start, end 파라미터 없이 호출
print(list1)

# 테스트 2
list2 = [28, 13, 9, 30, 1, 48, 5, 7, 15]
quicksort(list2) # start, end 파라미터 없이 호출
print(list2)

# 테스트 3
list3 = [2, 5, 6, 7, 1, 2, 4, 7, 10, 11, 4, 15, 13, 1, 6, 4]
quicksort(list3) # start, end 파라미터 없이 호출
print(list3)


728x90
반응형

'알고리즘 > 알고리즘 이론' 카테고리의 다른 글

힙 자료구조  (0) 2021.05.04
DFS / BFS  (0) 2021.04.12
재귀 함수  (0) 2021.04.02
브루트 포스 (Brute Force)  (0) 2021.03.18
다이나믹 프로그래밍  (0) 2021.03.08
728x90
반응형

www.acmicpc.net/problem/2108

 

2108번: 통계학

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

www.acmicpc.net

문제

수를 처리하는 것은 통계학에서 상당히 중요한 일이다. 통계학에서 N개의 수를 대표하는 기본 통계값에는 다음과 같은 것들이 있다. 단, N은 홀수라고 가정하자.

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

N개의 수가 주어졌을 때, 네 가지 기본 통계값을 구하는 프로그램을 작성하시오.

입력

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

출력

첫째 줄에는 산술평균을 출력한다. 소수점 이하 첫째 자리에서 반올림한 값을 출력한다.

둘째 줄에는 중앙값을 출력한다.

셋째 줄에는 최빈값을 출력한다. 여러 개 있을 때에는 최빈값 중 두 번째로 작은 값을 출력한다.

넷째 줄에는 범위를 출력한다.

예제 입력 1

5 1 3 8 -2 2

예제 출력 1

2 2 1 10

예제 입력 2

1 4000

예제 출력 2

4000 4000 4000 0

예제 입력 3

5 -1 -2 -3 -1 -2

예제 출력 3

-2 -2 -1 2

 

[문제 해설]

문제에서 구할 것이 꽤 많다. 평균, 중앙값, 최빈값, 최대값과 최솟값의 차이이다. 하나씩 해결해 나가면 된다.

먼저 1번부터 구해보자.

n = int(sys.stdin.readline())

datas=[]
for _ in range(n):
    datas.append(int(sys.stdin.readline()))

def first(datas):
    return round(sum(datas)/len(datas))

여기서 까다로운 점은 소수점 첫째 자리에서 반올림한 값을 출력해야된다는 것이다. round함수를 사용하자. round함수에서 두번째 인수를 생략하면 앞에 인자에 가장 가까운 정수를 출력한다. 소수 첫째자리에서 반올림하고 싶은 것을 해결해 줄 수 있다. 

 

2번은 중앙값을 출력하는 것이다. 중간 인덱스를 변수로 저장하여 풀면 된다.

def second(datas):
    datas.sort()
    mid = (len(datas))//2
    return datas[mid]

3번은 어떻게 풀지 감이 아예 오지 않았다. 배열을 2개씩 만들어서도 풀려고 했는데 계속 실패하였다. 

찾아보니 최빈값은 모듈을 이용해서 쉽게 해결할 수 있었다. 

 

collections모듈에서 Counter클래스를 사용하는 것이다. 데이터의 개수를 셀 때 파이썬의 collections모듈의 Counter클래스가 유용하다.

 

Counter클래스는 파이썬의 기본 자료구조인 사전형을 확장하고 있기 때문에, 사전에서 제공하는 API를 그대로 사용할 수 있다. Counter 클래스는 데이터의 개수가 많은 순으로 정렬된 배열을 리턴하는 most_common이라는 메서드를 제공하고 있기 때문에 최빈값을 구하는데 사용할 수가 있다.

 

from collections import Counter

Counter('hello world').most_common() 
# [('l', 3), ('o', 2), ('h', 1), ('e', 1), (' ', 1), ('w', 1), ('r', 1), ('d', 1)]

다음과 같이 많은 순서대로 리턴할 수 있다. 이것을 최밴값에 사용해보자.

 

from collections import Counter
def third(datas):
    mode_dict = Counter(datas)
    modes = mode_dict.most_common()

    if len(datas) > 1:
        if modes[0][1] == modes[1][1]:
            mod = modes[1][0]
        else:
            mod = modes[0][0]
    else:
        mod = modes[0][0]

    return mod

modes[0][1]은 datas에서 제일 많이 나온 값의 개수를 의미 한다. 최빈값이 여러 개일 경우 두번째로 작은 값을 출력하라고 했으니 modes[0][1] == modes[1][1]일때 modes[1][0]을 출력하고 그렇지 않을때는 modes[0][0]을 출력하면 된다.

 

4번은 최대값에서 최소값을 빼면 된다.

 

모든 코드는 아래와 같다.

from collections import Counter
import sys
n = int(sys.stdin.readline())

datas=[]
for _ in range(n):
    datas.append(int(sys.stdin.readline()))

def first(datas):
    return round(sum(datas)/len(datas))

def second(datas):
    datas.sort()
    mid = (len(datas))//2
    return datas[mid]

def third(datas):
    mode_dict = Counter(datas)
    modes = mode_dict.most_common()

    if len(datas) > 1:
        if modes[0][1] == modes[1][1]:
            mod = modes[1][0]
        else:
            mod = modes[0][0]
    else:
        mod = modes[0][0]

    return mod

def fourth(datas):
    return max(datas)-min(datas)

print(first(datas))
print(second(datas))
print(third(datas))
print(fourth(datas))
728x90
반응형
728x90
반응형

www.acmicpc.net/problem/11047

 

11047번: 동전 0

첫째 줄에 N과 K가 주어진다. (1 ≤ N ≤ 10, 1 ≤ K ≤ 100,000,000) 둘째 줄부터 N개의 줄에 동전의 가치 Ai가 오름차순으로 주어진다. (1 ≤ Ai ≤ 1,000,000, A1 = 1, i ≥ 2인 경우에 Ai는 Ai-1의 배수)

www.acmicpc.net

문제

준규가 가지고 있는 동전은 총 N종류이고, 각각의 동전을 매우 많이 가지고 있다.

동전을 적절히 사용해서 그 가치의 합을 K로 만들려고 한다. 이때 필요한 동전 개수의 최솟값을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N과 K가 주어진다. (1 ≤ N ≤ 10, 1 ≤ K ≤ 100,000,000)

둘째 줄부터 N개의 줄에 동전의 가치 Ai가 오름차순으로 주어진다. (1 ≤ Ai ≤ 1,000,000, A1 = 1, i ≥ 2인 경우에 Ai는 Ai-1의 배수)

출력

첫째 줄에 K원을 만드는데 필요한 동전 개수의 최솟값을 출력한다.

예제 입력 1

10 4200

1

5

10

50

100

500

1000

5000

10000

50000

예제 출력 1

6

예제 입력 2

10 4790

1

5

10

50

100

500

1000

5000

10000

50000

예제 출력 2

12

 

[문제 해설]

n종류의 동전으로 k금액을 만들면 된다. 그리디 알고리즘을 이용해 풀 수 있는 대표적인 문제로 간단한 아이디어만 떠올릴 수 있으면 된다. 그것은 바로 '가장 큰 화폐 단위부터' 나누어 주는 것이다. 물론 k보다 큰 금액이면 나눌 수 없으므로 k보다 작은 것중에 제일 큰 수부터 나누면 된다.

n,k=map(int,input().split())
a=[]
for _ in range(n):
    a.append(int(input()))
a.sort(reverse=True)
ans=0
for i in range(n):
    if a[i]>k:
        continue
    else:
        ans+=k//a[i]
        k=k%a[i]
print(ans)

 

그리디 알고리즘은 모든 알고리즘 문제에 적용할 수 있는 것은 아니다. 대부분의 문제는 그리디 알고리즘을 이용했을 때 '최적의 해'를 찾을 수 없을 가능성이 많다. 

 

사실 그냥 머리에 떠올린대로 그리디 해법을 생각했을때 해법이 정당한지 컴토해야 한다. 여기서 그리디 알고리즘을 검증하려면 조건을 유심히 봐야된다.

 

 괄호 안에 주어진 조건을 자세히 살펴보자. 이 문제에서는 조건이 중요하다.

(1 ≤ Ai ≤ 1,000,000, A1 = 1, i ≥ 2인 경우에 Ai는 Ai-1의 배수) Ai는 Ai-1의 배수라는 점. 그리디 알고리즘의 정당성을 부여하려면 예시를 들어보자. 만약 k의 값이 800원이고 Ai 배열에서 500원, 400원, 100원이라면 우리가 짠 그리디 알고리즘으로는 500원 1개, 100원 3개가 최적의 답으로 나온다. 그러나 사실 400원 2개 주는 것이 더 이득이다. 이 문제는 다이나믹 알고리즘으로 따로 풀 수 있다.

 

 이 문제에서 그리디 알고리즘을 쓸 수 있었던것은 Ai는 Ai-1의 배수라는 사실 때문이다.

아래에서 더 자세히 설명해 두었다.

2020.10.02 - [알고리즘/알고리즘 이론] - 그리디(Greedy) 알고리즘

 

그리디(Greedy) 알고리즘

 그리디Greedy 알고리즘은 단순하고 강력한 알고리즘이다.('탐욕법'이라고 불린다.) 그리디 알고리즘은 '매 선택에서 지금 이 순간 당장 최적인 답을 선택하여 적합한 결과를 도출하는 알고리즘'

jobdong7757.tistory.com

 

728x90
반응형
728x90
반응형

www.acmicpc.net/problem/1012

 

1012번: 유기농 배추

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

www.acmicpc.net

[문제 풀이]

문제가 길지만 정리하자면 배추밭에서 1이 있는곳은 배추가 있는곳, 0은 배추가 없는 곳이다. 1이 있는 곳을 DFS해서 주위에 0으로 둘러쌓일때까지 구하고, 그 갯수를 파악해서 출력하면 된다. 혹은 BFS를 통해서 풀 수 있다. (복습을 할 때 BFS를 통해서 풀었다.)

 

1. 첫번째 풀이법

import sys
sys.setrecursionlimit(10000)
def dfs(x,y):
    if x<=-1 or x>=n or y<=-1 or y>=n:
        return False
    if graph[x][y]==1:
        graph[x][y]=0
        dfs(x-1,y)
        dfs(x+1,y)
        dfs(x,y+1)
        dfs(x,y-1)
        return True
    return False
t = int(input())
for _ in range(t):
    m,n,k=map(int,input().split())
    graph=[[0]*(m) for _ in range(n)]
    result=0
    for _ in range(k):
        x,y=map(int,input().split())
        graph[y][x]=1
    for i in range(n):
        for j in range(m):
            if dfs(i,j):
                result+=1
    print(result)

dfs 함수를 정의해 주면서 먼저 x와 y좌표가 범위를 벗어날때는 False를 반환하게 두었다. 그러나 이렇게 하면 만약 x,y 에 (0,0) 이 들어갔을 경우 index error가 일어나게 된다. 

 

2. 두번째 풀이법

import sys
sys.setrecursionlimit(10000)
def dfs(x,y):
    dx=[0,0,1,-1]
    dy=[1,-1,0,0]
    for i in range(4):
        nx,ny = x+dx[i],y+dy[i]
        if nx>=n or nx<0 or ny>=m or ny<0:
            continue
        if graph[nx][ny]==1:
            graph[nx][ny]=0
            dfs(nx,ny)
t = int(input())
for _ in range(t):
    m,n,k=map(int,input().split())
    graph=[[0]*(m) for _ in range(n)]
    result=0
    for _ in range(k):
        x,y=map(int,input().split())
        graph[y][x]=1
    for i in range(n):
        for j in range(m):
            if dfs(i,j):
                result+=1
    print(result)

   

두 번째 풀이법은 dx, dy를 통해서 상하좌우를 탐색하기 때문에 상관없지만 첫번째 풀이법은 의도치 않은 인덱스에 접근할 수 있기때문에 오류가 난다.

 

3. 세번째 풀이 (BFS를 통해서 해결)

BFS를 통해서 푸는 것으로 익숙해질려고 했다.(DFS를 사용하니까 계속 recursion error 같은 것들을 신경써야해서..) 먼저 BFS는 deque를 사용하므로 상단에 deque를 import 시켜준다.

from collections import deque

bfs는 파라미터로 a,b를 받는다. 여기서 a, b는 배추밭에서 1인 것, 즉 배추가 있는곳을 찾으면 bfs를 실행해서 주위가 0으로 둘러쌓인것에 닿을때까지 실행해준다. 그리고 bfs함수가 끝나면 total_num(우리가 출력해야 되는 값)을 하나 더해준다.

 매번 헷갈리지만 주의해야 할 것은 2차원 배열에 x,y축의 값이다.. 가로가 m이지만 배열의 첫번째는 y축의 값이 들어가는.. 이런것을 계속 생각해주어야 한다. 

from collections import deque
def bfs(a,b):
    q=deque([])
    q.append((a,b))
    graph[a][b]=0
    dx=[-1,1,0,0]
    dy=[0,0,-1,1]
    bechu = 0
    while q:
        x,y=q.popleft()
        for i in range(4):
            nx = x+dx[i]
            ny = y+dy[i]
            if nx>=0 and nx<n and ny>=0 and ny<m and graph[nx][ny]==1:
                q.append((nx,ny))
                graph[nx][ny]=0
t = int(input())
for _ in range(t):
    m,n,k = map(int,input().split())
    graph=[[0]*(m) for _ in range(n)]
    total_num = 0
    for i in range(k):
        x,y = map(int,input().split())
        graph[y][x]=1
    for i in range(n):
        for j in range(m):
            if graph[i][j]==1:
                bfs(i,j)
                total_num+=1
    print(total_num)
728x90
반응형
728x90
반응형

display의 종류

모든 요소는 딱 한 개의 display 값을 갖고 있다. 

  1. inline
  2. block
  3. inline-block -> 같은줄에 있으면서 크기 설정하고 싶을때
  4. flex
  5. list-item
  6. none

대부분의 요소들은 inline과 block 중 한 가지이다.

inline display

ex)<span>, <b>, <i>, <img>, <button>

다른 요소들과 같은 줄에 머무르려고 함

가로 길이는 필요한 만큼만 차지하는 성향

 

block display

ex) <div>, <h1>, <p>, <nav>, <ul>, <li>

새로운 줄로 가려고 함

가로 길이를 최대한 많이 차지하려고 하는 성향

 

display 바꾸기

만약 inline display 속성을 썼는데 block으로 바꾸려고 하려면 CSS에서 바꾸어주면 된다.

ex)

i{
 display:block;
}

 

img 태그

<img>태그는 사실 대체 요소(replaced element)라고 하는 특별한 요소이다. inline-block은 아니지만 가로, 세로 길이를 설정할 수 있는 inline요소.

예를 들어 vertical-align도 사용할 수 있다. text-align:center;를 하면 가운데 정렬도 된다.

그러나 이미지와 텍스트를 같이 쓰는 경우가 아니면 margin-left:auto;와 margin-right:auto;를 사용해서 가운데 정렬하는 것이 좋다.

vertical - align

vertical-align 속성을 따로 쓰지 않으면 baseline으로 되어있다.

vertical-align:top을 쓴다면 가장 높은 요소에 맞춰진다.

vertical-align:bottom을 쓴다면 가장 낮은 요소에 맞춰진다.

 

baseline은 가만히 있지 않고 계속 움직인다. 

baseline은 vertical-align의 조건들을 충족시키면서 줄의 높이를 최소화시키는 곳에 위치한다.

 

어디로 맞춰질지 궁금하면 부모태그에 x를 입력해서 확인하자.

 

세로 가운데 정렬 꿀팁

가로 가운데 정렬

inline 요소

inline 또는 inline-block 요소면 부모 태그에 text-align:center;를 써주면 된다.

 

block 요소

margin-left:auto;, margin-right: auto;를 써주면 된다.

 

 

세로 가운데 정렬

 

가짜 요소 더하기

 

vertical-align 속성은 인라인 또는 인라인 블록 요소에 적용된다. vertical-align: middle; 은 요소의 가운데를 부모 요소의 가운데와 맞춘다.

 

세로 길이가 100%인 div 요소를 만들고, 그 요소에도 vertical-align: middle;을 하면 된다.

그렇게 하고 그 요소의 가로 길이를 없애면 된다.

 

글자를 감싸는 박스의 높이와 같은 크기로 line-height속성을 지정해주면 글자가 수직 중앙 정렬된다.

 

line-height는 div 부모 태그에 설정해주면 되고 자식태그에는 line-height를 상속받지 않으려면

line-height:normal;을 써주면 된다.

 

 

728x90
반응형

'프론트엔드 > HTML CSS' 카테고리의 다른 글

CSS 포지셔닝  (0) 2021.04.13
CSS 활용하기  (0) 2021.04.11
웹에서의 박스 모델(Box Model) 다루기  (0) 2021.04.09
HTML, CSS, JavaScript  (0) 2021.04.02
728x90
반응형

CSS에서 스타일링 해줄 요소는 '선택자' 로 결정한다.

 

1. 선택자 정리

 

 태그 이름

/* 모든 <h1> 태그 */
h1 {
  color: orange;
}

클래스 / 아이디

/* 'important'라는 클래스를 갖고 있는 모든 태그 */
.important {
  color: orange;
}

/* 'favorite'라는 아이디를 갖고 있는 태그 */
#favorite {
  color: blue;
}

자식(children)

/* 'div1' 클래스를 갖고 있는 요소의 자식 중 모든 <i> 태그 */
.div1 i {
  color: orange;
}

직속 자식(direct children)

/* 'div1' 클래스를 갖고 있는 요소의 직속 자식 중 모든 <i> 태그 */
.div1 > i {
  color: orange;
}

 

복수 선택

/* 'two' 클래스를 가지고 있는 태그 모두와 'four' 클래스를 가지고 있는 태그 모두 선택 */
.two, .four {
  color: orange;
}

여러 조건

/* 'outside' 클래스를 갖고 있으면서 'one' 클래스도 갖고 있는 태그 */
.outside.one {
  color: blue;
}

/* 'inside' 클래스를 갖고 있으면서 'two' 클래스도 갖고 있는 태그 */
.inside.two {
  color: orange;
}

 

Pseudo-class(가상 클래스)

콜론(:)을 사용하면 몇 가지 '가상 클래스'를 선택할 수 있다.

n번째 자식

<div class="div1">
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
  <p>Paragraph 3</p>
  <p>Paragraph 4</p>
  <p>Paragraph 5</p>
  <p>Paragraph 6</p>
</div>
/* .div1의 자식인 <p> 태그 중 3번째 */
.div1 p:nth-child(3) {
  color: blue;
}

/* .div1의 자식인 <p> 태그 중 첫 번째 */
.div1 p:first-child {
  color: red;
}

/* .div1의 자식인 <p> 태그 중 마지막 */
.div1 p:last-child {
  color: green;
}

/* .div1의 자식 중 마지막 자식이 아닌 <p> 태그 */
.div1 p:not(:last-child) {
  font-size: 150%;
}

/* .div1의 자식 중 첫 번째 자식이 아닌 <p> 태그 */
.div1 p:not(:first-child) {
  text-decoration: line-through;
}

0번째 부터가 아니고 first-child가 첫번째 요소이다.

 

마우스 오버(hover)

h1 {
  color: orange;
}

/* 마우스가 <h1> 태그에 올라갔을 때 */
h1:hover {
  color: green;
}

 

 

2. CSS 상속

 

css에는 '상속' 개념이 있다. 부모 요소의 속성들을 자식들한테 넘겨주는 것이다. 큰 div태그가 있으면 그 안에 들어가있는 속성들은 모두 div태그의 css속성 값에 따라 같이 적용되는 것이다. 

하지만 태그와 속성에 따라 상속이 되지 않는 경우도 있다. 예를 들어서 부모 태그에 설정한 margin이 모든 자식들에게 적용은 되지 않는다. 

 

웬만하면 상속되는 몇 가지 속성들

  1. color
  2. font-family
  3. font-size
  4. font-weight
  5. line-height
  6. list-style
  7. text-align
  8. visibility

웬만하면 이라고 한 이유는 항상 상속되는 것은 아니기 때문이다. 예를들어 <a>태그에는 color 속성이 상속되지 않는다. <a>태그가 억지로 상속을 받아오기 위해서는 해당 속성에 inherit 값을 쓰면 된다.

<div class="div1">
  Let's go to <a href="https://google.com" target="_blank">google</a>!
</div>

<div class="div2">
  Let's go to <a href="https://google.com" target="_blank">google</a>!
</div>
.div1 {
  color: green;
}

.div2 {
  color: orange;
}

.div2 a {
  color: inherit;
}

 

3. CSS 우선 순위

여러 선택자가 같은 요소를 가리키면 우선 순위를 어떻게 평가할까.

 

1. 완전 똑같은 선택자가 나중에 또 나오면, 이전에 나온 스타일을 덮어쓰게 된다.

h1 {
  color: blue;
  text-align: center;
}

h1 {
  color: green;
}

//h1 태그는 초록색으로 된다.

 

2. 명시도(Specificity)

같은 요소를 가리키지만 선택자가 다르다면, '명시도(specificity)'에 따라 우선 순위가 결정된다.

 

명시도 계산기

  1. 인라인 스타일이 가장 우선 순위가 높다.
  2. 선택자에 id가 많을 수록 우선 순위가 높다.
  3. 선택자에 class, attribute, pseudo-class가 많을 수록 우선 순위가 높다.
  4. 그 다음은 그냥 요소(또는 가상 요소)가 많은 순서이다.

<ul> 태그 안에 <li> 태그 안에 <a id="link">가 있다고 가정해보자. 

<ul>
  <li><a id="link" href="#">Link 1</a></li>
  <li><a id="link" href="#">Link 1</a></li>
  <li><a id="link" href="#">Link 1</a></li>
  <li><a id="link" href="#">Link 1</a></li>
</ul>
ul li:first-child #link {
  color: green;
}

ul li:first-child a {
  color: orange;
}


/*첫번째 것이 요소의 명시도가 높으므로 첫번째 css가 적용된다*/

 

4. CSS의 다양한 단위들

 css에는 px, rem, em, %등 여러 단위가 있다. 폰트 크기 뿐만 아니라 padding, margin, width 등 다양한 속성들에 이 단위들을 사용할 수 있다.

 

1. px 

 절대적인 값. 다른 요소의 값에 영향을 받지 않는다.

 

2. rem

상대적인 값. 하지만 오직 <html> 태그의 font-size에만 영향을 받는다.

2rem은 <html>태그의 font-size의 2배 크기이다.

 

3. em

em도 rem과 마찬가지로 상대적인 값이다. em은 자기 자신의 font-size를 기준으로 한다.

2em은 자기 자신의 font-size의 2배 크기이다. 자기 자신의 font-size를 따로 정해주지 않을 경우, 상위 요소에서 상속받은 값을 기준으로 한다.

만약 자신에게 정해진 font-size가 있다면 그 값을 기준으로 em이 결정된다.

 

4. 퍼센트 %

%는 어느 항목에서 쓰이냐에 따라 다른 기준이 적용된다.

예를 들어 font-size에서 %가 쓰일 경우, 상위 요소의 font-size에 곱해주는 방식으로 계산.

%가 margin이나 padding의 단위로 사용될 경우, 상위 요소의 width를 기준으로 계산된다.

margin-top이나 padding-bottom 등 세로 속성을 조절할 때에도 상위 요소의 height가 아닌 width를 기준으로 계산된다.

728x90
반응형

'프론트엔드 > HTML CSS' 카테고리의 다른 글

CSS 포지셔닝  (0) 2021.04.13
display 속성  (0) 2021.04.11
웹에서의 박스 모델(Box Model) 다루기  (0) 2021.04.09
HTML, CSS, JavaScript  (0) 2021.04.02
728x90
반응형

www.acmicpc.net/problem/11724

 

11724번: 연결 요소의 개수

첫째 줄에 정점의 개수 N과 간선의 개수 M이 주어진다. (1 ≤ N ≤ 1,000, 0 ≤ M ≤ N×(N-1)/2) 둘째 줄부터 M개의 줄에 간선의 양 끝점 u와 v가 주어진다. (1 ≤ u, v ≤ N, u ≠ v) 같은 간선은 한 번만 주

www.acmicpc.net

문제

방향 없는 그래프가 주어졌을 때, 연결 요소 (Connected Component)의 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 정점의 개수 N과 간선의 개수 M이 주어진다. (1 ≤ N ≤ 1,000, 0 ≤ M ≤ N×(N-1)/2) 둘째 줄부터 M개의 줄에 간선의 양 끝점 u와 v가 주어진다. (1 ≤ u, v ≤ N, u ≠ v) 같은 간선은 한 번만 주어진다.

출력

첫째 줄에 연결 요소의 개수를 출력한다.

 

예제 입력 1

6 5
1 2
2 5
5 1
3 4
4 6

예제 출력 1

2

 

 

예제 입력 2

6 8
1 2
2 5
5 1
3 4
4 6
5 4
2 4
2 3

예제 출력 2

1

 

[문제 해설]

먼저 문제를 해결하려면 연결 요소라는 개념을 알아야 한다. 연결요소란 그래프의 개수와 같다. 정점 사이에 겹쳐진게 없고, 나누어진 각각의 그래프를 연결 요소라고 생각하면 된다. 연결 요소를 구하는 것은 DFS나 BFS 탐색을 이용해서 할 수 있다.

 

정점의 개수 n과 간선의 개수 m을 먼저 입력 받는다. 그리고 graph라는 2차원 배열을 만들어서 연결된 정보를 얻는다. visited 배열은 각각의 정점에 방문했는지 확인하는것으로 False로 초기화시켜놓는다. 

 

dfs함수를 만들면 되는데 파라미터로는 v, 즉 노드를 받는다. visited[v]를 True로 대입하고 v와 연결된 곳 중 방문하지 않은 곳을 dfs해준다. 이렇게 dfs를 다 하면 result값을 1 추가한다. 출력값은 result를 출력하면 되는것이다.

 

import sys
sys.setrecursionlimit(10000)

n,m = map(int,input().split())
graph=[[] for _ in range(n+1)]
visited=[False]*(n+1)
result=0
for _ in range(m):
    u,v = map(int,input().split())
    graph[u].append(v)
    graph[v].append(u)

def dfs(v):
    visited[v]=True
    for i in graph[v]:
        if not visited[i]:
            dfs(i)
for i in range(1,n+1):
    if not visited[i]:
        dfs(i)
        result+=1
print(result)

 

##의문점##

이 문제를 제출하니까 pypy3으로는 해결되는데 python3으로는 시간초과가 난다. 그래서 질문을 올렸더니...

www.acmicpc.net/board/view/66897#comment-111276

 

글 읽기 - python3으로는 시간초과가 나는데 pypy3으로는 해결되었습니다

댓글을 작성하려면 로그인해야 합니다.

www.acmicpc.net

파이썬 루프쪽 구현을 잘못해서 pypy구현체가 훨 빠르다고... 

(나중에 확인해봐야겠다)

728x90
반응형
728x90
반응형

요소는 내용(content), 패딩(padding), 테두리(border)로 이루어져 있다. Padding은 내용과 테두리 사이의 공간이다.

Margin은 요소 주위의 여백, 즉 테두리 밖의 공간이다.

 

Margin과 Padding 사용법

padding은 다음과 같이 사용한다.

p {
  padding: 위 오른쪽 아래 왼쪽;
}
p {
  padding: 20px 60px 40px 120px;
}

위, 아래, 왼쪽, 오른쪽이 다 같은 경우

만약 위, 아래, 왼쪽, 오른쪽에 똑같은 padding을 주고 싶으면 더 간편하다. 모두 50px의 padding을 주려면 이렇게 하면 된다.

p {
  padding: 50px;
}

 

Margin도 사용방법이 같기 때문에 따로 코드를 보여주진 않겠다.

 

요소를 가운데 정렬하고 싶으면 왼쪽과 오른쪽 margin 값을 auto로 설정해줘야 한다. auto는 말 그대로 '자동으로 계산'하라는 뜻이다. 왼쪽과 오른쪽을 auto로 설정하면 자동으로 왼쪽과 오른쪽으로 똑같이 함으로써 요소는 가운데 정렬이 된다.

p {
  margin-left: auto;
  margin-right: auto;
}

Overflow 정리

width, height, max-width, max-height 등을 설정하다 보면 내용물이 들어갈 공간이 부족한 경우가 생긴다. 그럴때 overflow를 사용하여 보여주던가 scroll하던가 숨겨주던가 한다.

 

1. visible : 넘쳐나는 내용물이 그대로 보여진다. 디폴트 값이다.

p {
  overflow: visible;
}

2. hidden : 넘쳐나는 부분 아예 숨기기

p {
  overflow: hidden;
}

3. scroll : 내용물을 숨겼다가, 사용자가 스크롤을 하면 볼 수 있게 해주는 방법

p {
  overflow: scroll;
}

4. auto : scroll과 거의 똑같음. scroll은 항상 스크롤바를 보여주고, auto는 내용물이 넘쳐날 때만 스크롤바 보여줌

p {
  overflow: auto;
}

border 정리

border 속성 값을 쓰는 순서는 굵기, 스타일(실선, 점선 등), 색.

.p1 {
  border: 2px solid #4d9fff;
}

아니면 명확하게 나눠서 사용하면 된다.

border-width , border-style, border-color 순서대로 이다.

 

border-style 에는 dotted, dashed, solid 등이 있다.

 

border를 없애기 위해서는 

border: none;

border: 0;

둘 중 하나를 사용하면 된다.


박스 꾸미는 몇 가지 방법

1. border-radius -> 둥근 모서리 쓰기

(border-top-left-radius, border-top-right-radius, border-bottom-right-radius 이런식으로 각 모서리를 개별 설정 가능)

 

2. backgroud-color -> 배경색 사용하기

 

3. backgroud-color: transparent -> 배경색 투명하게

 

4. box-shadow: 10px 10px 10px 10px red-> 그림자 입히기

(순서대로 1. 위쪽 2. 오른쪽 3. 흐리게 나오는 정도(blur : 기본값 0px) 4. 그림자 크기 설정(spread) 5. 색깔)


box - sizing

width와 height가 border, padding을 뺀 내용물의 크기만 나타나기 때문에 결과물은 달라질 수 있다. width, padding, border를 쓰다보면 원하는 가로 길이를 계산하기 귀찮아지기 때문에 box-sizing으로 간편하게 할 수 있다. 기본값은 box-sizing:content-box;이다.

h1{
 box-sizing:content-box;
}

box-sizing: border-box; 는 너무 편리해서 자주 사용한다.

모든 요소에 쓰고 싶으면 *을 쓰고 속성을 써주면 된다.

*{
 box-sizing:border-box;
}

배경 이미지

background-image:url("")

1. background-repeat

 이미지를 반복시킬 것인지 아닐 것인지, 그리고 반복시킨다면 어떤 방식으로 반복시킬 것인지 정해주는 속성이다.

/* 반복하지 않음 */
background-repeat: no-repeat;

/* 가로 방향으로만 반복 */
background-repeat: repeat-x;

/* 세로 방향으로만 반복 */
background-repeat: repeat-y;

/* 가로와 세로 모두 반복 */
background-repeat: repeat;

/* 반복할 수 있는 만큼 반복한 뒤, 남는 공간은 이미지 간의 여백으로 배분 */
background-repeat: space;

/* 반복할 수 있는 만큼 반복한 뒤, 남는 공간은 이미지 확대를 통해 배분 */
background-repeat: round;

 

2. background-size

 배경 이미지의 사이즈를 정해주는 속성이다.

/* 원래 이미지 사이즈대로 출력 */
background-size: auto;

/* 화면을 꽉 채우면서, 사진 비율을 유지 */
background-size: cover;

/* 가로, 세로 중 먼저 채워지는 쪽에 맞추어서 출력 */
background-size: contain;

/* 픽셀값 지정 (가로: 30px, 세로: 50px로 설정) */
background-size: 30px 50px;

/* 퍼센트값 지정 (가로: 부모 요소 width의 60%, 세로: 부모 요소 height의 70%로 설정) */
background-size: 60% 70%;

 

3. background-position

 배경 이미지의 위치를 정해주는 속성이다.

/* 단어로 지정해주기 (가로: left, center, right, 세로: top, center, bottom) */
/* 아래와 같은 총 9개의 조합이 가능 */
background-position: left top;
background-position: left center;
background-position: left bottom;
background-position: right top;
background-position: right center;
background-position: right bottom;
background-position: center top;
background-position: center center;
background-position: center bottom;

/* 퍼센트로 지정해주기 (가로: 전체 width의 25% 지점, 세로: 전체 height의 75% 지점 ) */
background-position: 25% 75%;

/* 픽셀로 지정하기 (가로: 가장 왼쪽 가장자리에서부터 오른쪽으로 100px 이동한 지점, 세로: 가장 상단 가장자리에서 아래로 200px 이동한 지점) */
background-position: 100px 200px;
728x90
반응형

'프론트엔드 > HTML CSS' 카테고리의 다른 글

CSS 포지셔닝  (0) 2021.04.13
display 속성  (0) 2021.04.11
CSS 활용하기  (0) 2021.04.11
HTML, CSS, JavaScript  (0) 2021.04.02

+ Recent posts