문제출처 : https://www.acmicpc.net/problem/1325


1. 문제요약

- N개의 컴퓨터, 1 <= N <= 10,000

- M개의 신뢰관계, 1 <= M <= 100,000

- A가 B를 신뢰한다. => B를 해킹하면 A도 해킹할 수 있다. / A를 해킹하면 B는 해킹할 수 없다.

- M개의 A B 쌍이 주어지며, A가 B를 신뢰한다.

- 한 번에 가장 많은 컴퓨터를 해킹 할 수 있는 컴퓨터의 번호를 오름차순 출력


2. 접근방법

- 단뱡향 그래프

- 신뢰관계에 대해 int 더블배열을 쓰면 4 * 10,000 * 10,000 = 400,000,000byte = 400Mbyte로 메모리 초과

  => 더블 벡터로 입력 받음

- 하나의 컴퓨터에서 해킹 할 수 있는 모든 컴퓨터를 찾는다.

- 한 정점에서 시작하여 다시 그 정점을 방문하면 안되므로 체크 배열을 쓴다.


3. 시간복잡도

- 모든 정점의 갯수 N * 최대 쌍의 갯수 M = O(NM)

- NM = 10억 인데 5초 안에 들어오려나...3.8초 나옴

- SCC 라는 알고리즘을 쓰면 더 빨리 돌릴 수 있다는데 나중에 공부해야지


4. 회고

- 중간에 dp 처럼 아에 한번 방문한 정점은 다시는 방문하지 않아도 되지 않을까 해서 그렇게 했는데

  이렇게 하면 체크가 없어서 그래프가 싸이클을 만들면 무한루프로 빠져들어감......

  => 그래프에서는 싸이클을 생각해보자


- 한 정점(1 번)에서 시작해서 방문했던 정점을 재 방문 하는 경우(1 -> 2 -> 1)만 막아야지

  새로운 다른 정점(2 번)에서 시작해서 이전 정점에서 방문했던 정점(1 번에서 방문했던 정점들) 방문을 막으면 안됨

  쌍방 연결이나, 한 노드를 여러 노드가 방문할 수 있기 때문

  => 체크 배열 초기화 !!!!!!!


- 컴퓨터의 번호는 1 부터 시작하므로 배열의 크기는 n + 1 !!!!!!!!!

  for문 인덱스도 1 !!!!!!!



소스코드



[출처 : BOJ, 문제에 대한 모든 권리는 BOJ(acmicpc.net, startlink)에 있음]

'먹고살려면 > boj' 카테고리의 다른 글

BOJ 1389 케빈 베이컨의 6단계 법칙  (0) 2018.01.04
BOJ 9205 맥주 마시면서 걸어가기  (0) 2018.01.03
BOJ 2667 단지번호붙이기  (0) 2017.12.27
BOJ 10448 유레카 이론  (0) 2017.12.26
BOJ 2231 분해합  (0) 2017.12.26

문제출처 : https://www.acmicpc.net/problem/2667


1. 문제요약

- N*N 맵, 5 <= N <= 25

- 0 빈공간 / 1 집

- 상하좌우로 연결된 집을 하나의 단지

- 단지의 갯수와 각 단지별 집의 갯수를 오름차순으로 출력


2. 접근방법

- 방문한적이 없고, 집이면 방문해서 상하좌우로 연결된 모든집을 방문하여 단지를 만듬

- 단지를 만들면서 집의 갯수를 같이 셈

- bfs / dfs 모두 가능


3. 시간복잡도

- 모든 칸을 한번씩 방문하므로 N^2 = 625


4. 회고

- 전역변수를 안쓰고 리턴값을 쓰니까 조금 귀찮기는 한데 초기화를 안해도 되서 

- 나름의 장단점이 있는데 음...


- 방문한 집이면 맵 자체를 1 -> 0 으로 바꾸면 check 배열을 안써도 됨

- cin 만 쓰려니 공백없는 정수를 받을때는 불편함...


- sort 없이 1차원 배열을 최대 집 갯수 만큼 선언해서 단지 갯수를 입력함.

a[집 갯수] = 단지 갯수
for(int i = 0; i < n*n + 1; i++){
    for(int j = 0; j < a[i]; j++){
        cout << i << "\n";
    }
}

18.2.7

소스코드 수정 - num이 필요없잖아.. 벡터를 쓰는데

dfs만 수정함


소스코드 : dfs


소스코드 : bfs


[출처 : BOJ, 문제에 대한 모든 권리는 BOJ(acmicpc.net, startlink)에 있음]

'먹고살려면 > boj' 카테고리의 다른 글

BOJ 9205 맥주 마시면서 걸어가기  (0) 2018.01.03
BOJ 1325 효율적인 해킹  (0) 2017.12.27
BOJ 10448 유레카 이론  (0) 2017.12.26
BOJ 2231 분해합  (0) 2017.12.26
BOJ 1966 프린터 큐  (0) 2017.12.26

문제출처 : https://www.acmicpc.net/problem/10448


1. 문제요약

- Tn = n(n+1)/2

- 자연수 K가 주어졌을 때 세개의 Tn 으로 나타낼 수 있으면 1, 없으면 0

- 3 <= K <= 1,000


2. 접근방법

- Tn이 몇개나 필요할까? => n(n+1)/2 <= 1,000 을 만족하는 n은 대충 44, 45

- T1 ~ T45 까지 3개를 뽑으면 되므로 45 * 45 * 45 = 91,125 이므로 1초 내에 들어옴

- 즉, 브루트 포스


- 여기서 45 * 45 * 45는 중복이 포함

- T1 + T1 + T2 / T1 + T2 + T1 / T2 + T1 + T1 은 같은 경우 이므로 제외 하면 조금 더 빨라 지겠지?

※ 실제로 다 해본 경우는 32ms / 중복 제외한 경우는 28ms


3. 시간복잡도

- N^3 = 91,125


4. 회고

- 미리 결과 합을 구해두면 출력에 편함

- 어차피 시간내에 들어오므로 굳이 안해도 됨


- 미리 구한 다른 사람은 0ms 인데 난 왜 28ms 이냐!!!

- 싱크 안맞춘 cin 때문인가.... T의 갯수가 몇개인지 모르니


- 미리 세개의 합을 구한 배열을 지역변수에서는 T45 + T45 + T45 = 3105 이상으로 잡아야 오버 인덱스 안남

  전역변수로 선언한다면 100 개 정도는 더 잡아주는 거 같음 3000개로도 통과되네



소스코드



[출처 : BOJ, 문제에 대한 모든 권리는 BOJ(acmicpc.net, startlink)에 있음]

'먹고살려면 > boj' 카테고리의 다른 글

BOJ 1325 효율적인 해킹  (0) 2017.12.27
BOJ 2667 단지번호붙이기  (0) 2017.12.27
BOJ 2231 분해합  (0) 2017.12.26
BOJ 1966 프린터 큐  (0) 2017.12.26
BOJ 7568 덩치  (0) 2017.12.19

문제출처 : https://www.acmicpc.net/problem/2231


1. 문제요약

- 어떤 자연수 M => 세 자릿수 라면 100a + 10b + c => M + a + b + c = N 즉, M과 각 자릿수의 합을 분해합, M을 생성자, N을 분해합

- 1 <= N <= 1,000,000 인 자연수 N이 주어 졌을 때 가장 작은 생성자는?


2. 접근방법

- 생성자는 분해합을 넘을 수 없으므로 1 부터 N-1 까지의 모든 수를 다 해보자


- 좀 더 생각해보면 분해합 N이 만들어 질 수 있는 생성자의 최대 자릿수는 6자릿수

  (생성자가 1,000,000 이면 분해합은 1,000,001 이므로 7 자릿수는 나올 수 없음)

  각 자릿수의 최대 값은 9

  즉, 생성자는 분해합 보다 54 이상 작을 수 없음.

  N-54 부터 N-1 까지만 찾으면 됨.

  가장 작은 수 부터 찾을 거니 처음 만나는 생성자가 최소값


3. 시간복잡도

- 두 가지 경우 모두 N

- 당연히 실제 시간은 전체 검색시 8ms / 55개 검사시 0ms


4. 회고

- 처음엔 다 했는데...

- 다른 사람의 소스 코드를 보고 깨달음

- 각 자릿수 합의 최대 범위



소스코드



[출처 : BOJ, 문제에 대한 모든 권리는 BOJ(acmicpc.net, startlink)에 있음]

'먹고살려면 > boj' 카테고리의 다른 글

BOJ 2667 단지번호붙이기  (0) 2017.12.27
BOJ 10448 유레카 이론  (0) 2017.12.26
BOJ 1966 프린터 큐  (0) 2017.12.26
BOJ 7568 덩치  (0) 2017.12.19
BOJ 6603 로또  (0) 2017.12.19

문제출처 : https://www.acmicpc.net/problem/1966


1. 문제요약

- 중요도에 따라 인쇄순서를 결정하고 특정 문서가 몇번째 출력되는가?

- 문서의 수 N <= 100, 0 <= 위치 M < N


2. 접근방법

- 일단 N이 얼마 안되기 때문에 브루트 포스

- 모든 문서가 큐에 저장

- 큐에 첫번째 문서가 출력 대상이 아니라면 뒤로 보냄

- 출력 대상이라면 출력


3. 시간복잡도

- Queue나 배열 하나만 쓴다면 N^3,

  출력 대상을 찾는데 하나의 문서와 모든 문서를 비교 해야 하므로 N^2, 

  모든 문서의 개수가 N 이므로 N^3


- Priority_Queue 라던가 가중치를 가지고 있다면,

  하나의 문서를 찾는데 N, 문서 전체의 개수가 N 이므로 N^2


4. 회고

- 배열을 큐처럼 만들어서 출력 대상이 아니면 배열 뒤에 붙이는 방식인 경우 최소 100 * 101 / 2 = 5050 이상 사이즈가 필요

- 인덱스만 가지고 움직인다면 배열 사이즈는 N이면 됨

  출력한 놈을 다시 출력하는 논리적 오류가 발생

  이런거 신경 안쓸려면 index를 출력한놈은 건너 뛰게 만들어야함


- 문서 번호와 문서 중요도를 보관해야 함

- 배열로 구현 했을 때 한칸씩 당기지 않으면 출력 했는지 안했는지 체크가 필요

- Queue 자료구조를 쓴다면 front를 뺄 때, 다른 자료와의 중요도를 비교할 수 있는 수단이 필요함

  하나씩 빼서 비교하던가 아니면 Priority_Queue나 중요도를 저장하고 있는 다른 배열과 비교가 필요



소스코드 : N^3



[출처 : BOJ, 문제에 대한 모든 권리는 BOJ(acmicpc.net, startlink)에 있음]

'먹고살려면 > boj' 카테고리의 다른 글

BOJ 10448 유레카 이론  (0) 2017.12.26
BOJ 2231 분해합  (0) 2017.12.26
BOJ 7568 덩치  (0) 2017.12.19
BOJ 6603 로또  (0) 2017.12.19
BOJ 1182 부분집합의 합  (0) 2017.12.16

3. 최적화 문제

- 경우의 수 문제와 같이 답이 여러개인 문제에서 '어떤 기준'에 따라 '좋은' 답을 찾는 문제를 '최적화 문제(Optimization Problem)'


※ 최적화 문제를 해결하는 방법

- 완전 탐색

- 동적 계획법

- 조합 탐색

- 결정 문제로 치환


=> 완전 탐색은 최적화 문제를 풀기 위한 가장 직관적인 방법



예제. 문제 : CLOCKSYNC

https://algospot.com/judge/problem/read/CLOCKSYNC


1) 문제를 읽고 이해하기

- 시간 제한 10ms / 메모리 제한 2^16kb

- 테스트 케이스의 개수 <= 30


2) 문제 재정의

- 16개의 시계, 3, 6, 9 12 만 가리킬 수 있음

- 10개의 스위치로 시간 조작 가능

- 각각의 스위치는 3~5개의 시계와 연결되어 있어서 해당 스위치를 누르면 연결된 시계들이 +3 씩 움직임

- 모두 12시를 가리키기 위해 눌러야 할 최소 스위치의 횟수

- 불가능할 경우 -1 출력


3) 계획 세우기

계획1.

- 최소 스위치 횟수 이기에 bfs를 고민함.

- 스위치를 몇 번 눌러야 할지 정해지지 않았기에 모든 상태를 저장하고 하나의 상태를 방문할 때 마다 저장된 상태와 비교하려고 함.

- 시계 하나는 3, 6, 9, 12 4가지 상태를 나타낼 수 있으므로 2bit로 표현 가능.

  16개의 시계 이므로 32bit 즉, int 하나로 16개 시계의 한 가지 상태를 저장 할 수 있음

  하지만, 메모리가 너무 크고 시간 예측이 안됨.

  큐 0회 : 4byte

  큐 1회 : 0 ~ 9번 버튼을 각각 눌렀을 때 10가지의 상태 : 40byte

  큐 2회 : 큐 1회에서 각각 10가지 경우가 또 발생 하므로 : 400byte

  큐 3회 : 4,000byte

  ... 큐 1회를 돌 때마다 10배가 늘어나므로 65,536,000 byte < 4 * 10^N => N이 8이면 메모리 초과


계획2.

- 시계가 3, 6, 9, 12로 회전 하므로 하나의 시계가 4회 이상 돌아갈 필요가 없음.

- '0번 버튼 -> 1번 버튼' 이나 '1번 버튼 -> 0번 버튼' 이나 결과는 똑같음

   012012나 001122는 결과가 같음

- 즉, 각각의 버튼은 0 ~ 3회만 누르면 되고 순서에 상관없음.

- 버튼을 누르는 횟수의 경우의 수는 4, 총 버튼의 개수가 10이므로 모든 경우의 수는 4^10


4) 계획 검증하기

- '계획1'은 이미 메모리 초과

- '계획2'는 4^10 == 2^20 ≒ 1억번


5, 6) 계획 수행하기 및 회고하기

- 문제 풀이 원리 : 다시 되돌아 오는 특징과 버튼의 순서가 중요하지 않다는 점이 버튼을 누르는 횟수를 제한 시킴

- 사실 아직도 4번 이상 누를 필요가 없는지에 대해서는 확신이 없음

- 나중에 내가 다시 풀 수 있을까?

- 비슷한 문제를 찾아봐야 겠음. 전구인가 색칠하기 인가 한칸 누르면 인접 4칸 색이 바뀌는 문제가 있었던거 같은데


- 구현 시 배열이라면 길이를 확인 또 확인....

- "Run-Time Check Failure#2 - Stack around the variable was corrupted" 에러는 포인터로 지역변수를 넘겼을 때 실제로 선언된 사이즈를 넘어선 인덱스로 입력을 시도할 때 발생함.


소스코드



4. 많이 등장하는 완전 탐색 유형

1) 모든 순열 만들기

- 가능한 모든 경우 : N!

- 실제로 만드는 방법은 다른 블로그 많으니 참고

- C++ 은 next_permutation(), prev_permutation()이 있음


2) 모든 조합 만들기

- 재귀

- nCr => 1개를 뽑고 n-1Cr-1을 재귀

- 코드 6.2 참고


3) 2^n가지 경우 만들기

- 'Yes / No' 의 경우 => 재귀 2^N

- Bit Mask를 이용하면 for문 하나로 모든 경우를 다 돌 수 있음



- 알고리즘 문제 해결전략 1편 중 -

- 저작권 문제시 삭제하겠습니다 -

'먹고살려면 > Algorithm' 카테고리의 다른 글

4편 그래프 : dfs 1  (0) 2017.12.29
3-2편 무식하게 풀기 2  (0) 2017.12.18
번외편 c/c++ 입력속도  (0) 2017.12.12
3-1편 무식하게 풀기 1  (0) 2017.12.11
2편 알고리즘 시간 복잡도 분석  (0) 2017.12.07

뜬금없이 궁금한 점이긴 한데


논리회로 공부를 하다가 보면 NAND gate를 배우기 마련


그럼 SSD에 들어가는 NAND Flash Memory에 NAND gate소자가 들어가서 NAND라는 이름이 붙은 걸까?


이유는 NAND flash memory 셀 어레이 회로 구조가 nMOS NAND gate의 회로 구조와 동일 하기 때문입니다.



                       

                               <fig 1>                                                                         <fig 2>



위 그림에서 <fig1>의 왼쪽 그림이 NAND flash memory의 셀 구조 입니다. 


<fig1>에 나온 memory의 일부를 '스트링'이라고 하는데 NAND는 스트링이 Bit Line과 Source Line을 공유하는 구조 입니다.


<fig2>는 nMOS NAND gate의 회로 인데 NAND flash memory 스트링의 회로와 같이 소스와 드레인을 공유하고 있습니다.


이때문에 <fig1>의 어레이를 구조 하고 있는 flash memory를 NAND flash memory 라고 부르게 되었습니다.



부족하거나 틀린점은 피드백 바랍니다.



출처

fig1 : https://www.omicsonline.org/open-access/nand-flash-memory-organization-and-operations-2165-7866-1000139.php?aid=46500

fig2 : https://upload.wikimedia.org/wikipedia/commons/4/49/NMOS_NAND.svg




참고자료

- NAND flash memory

https://gigglehd.com/zbxe/5791789

http://gamma0burst.tistory.com/593

https://www.omicsonline.org/open-access/nand-flash-memory-organization-and-operations-2165-7866-1000139.php?aid=46500


- NAND vs NOR

https://gigglehd.com/zbxe/5709833

http://slidesplayer.org/slide/11162137/


- NAND gate

https://ko.wikipedia.org/wiki/NAND_%EA%B2%8C%EC%9D%B4%ED%8A%B8


- NOR gate

https://ko.wikipedia.org/wiki/NOR_%EA%B2%8C%EC%9D%B4%ED%8A%B8





문제출처 : https://www.acmicpc.net/problem/7568


1. 문제요약

- n명 몸무게, 키가 주어짐

- 1번 몸무게 > 2번 몸무게 && 1번 키 > 2번 키 이면 1번이 2번 보다 덩치가 크다

- 나의 덩치 순위는 나보다 덩치큰 사람 + 1

- 2 ≤ n ≤ 50, 10 ≤ 몸무게, 키 ≤ 200


2. 접근방법

- 브루트 포스

- 한명을 기준으로 나머지(n-1)명의 덩치를 비교


3. 시간복잡도

- 한명을 기준으로 나머지(n-1)명의 덩치를 비교 : n-1

- 총 n명 이므로 : n * (n - 1) ≒ 2500


4. 회고

- 할게 없음


소스코드




[출처 : BOJ, 문제에 대한 모든 권리는 BOJ(acmicpc.net, startlink)에 있음]

'먹고살려면 > boj' 카테고리의 다른 글

BOJ 2231 분해합  (0) 2017.12.26
BOJ 1966 프린터 큐  (0) 2017.12.26
BOJ 6603 로또  (0) 2017.12.19
BOJ 1182 부분집합의 합  (0) 2017.12.16
BOJ 2309 일곱난쟁이  (0) 2017.12.13

문제출처 : https://www.acmicpc.net/problem/6603


1. 문제요약

- 원소 K개로 이루어진 집합 S (6 ≤ K ≤ 13)

- 집합 S에서 6개를 뽑는 경우의 수? (1 ≤ 원소 ≤ 49)

- 입력은 여러개 0 입력시 종료

- 사전 순 출력


2. 접근방법

- 조합 : 13C6


3. 시간복잡도

- 조합 : 1716


4. 회고

- 경우의 수 여서 브루트 포스

- 조합은 재귀나 다중 for문으로만 구현할 수 밖에 없나



소스코드 조합



[출처 : BOJ, 문제에 대한 모든 권리는 BOJ(acmicpc.net, startlink)에 있음]

'먹고살려면 > boj' 카테고리의 다른 글

BOJ 1966 프린터 큐  (0) 2017.12.26
BOJ 7568 덩치  (0) 2017.12.19
BOJ 1182 부분집합의 합  (0) 2017.12.16
BOJ 2309 일곱난쟁이  (0) 2017.12.13
BOJ 1065 한수  (0) 2017.12.12

예제. 문제 : BOARDCOVER

https://algospot.com/judge/problem/read/BOARDCOVER


1) 문제를 읽고 이해하기

- 시간제한 2ms / 메모리제한 2^16kb

- 1 <= h, w <= 20 / 흰칸의 수 <= 50


2) 문제 재정의

- 게임판의 흰칸( . )을 'ㄱ' 모양을 회전시킨 모양으로 전부 덮을 수 있는 경우의 수


3) 계획 세우기

- 경우의 수 문제이기에 일단 다해보는 '브루트 포스'

  : 블럭을 채워야 할 칸을 선택 후 적절한 블럭을 채움

  : 아직 채우지 않은 칸을 대상으로 위 과정을 반복함

  => '한 블럭'과 '나머지 칸'으로 문제를 분할 => 재귀


- 한 지점에서 시작하여 채우는 모양의 경우의 수가 16개

  최대 칸의 개수가 400개 이므로 중복되는 경우를 줄일 필요가 있음

- 재귀 호출 시 마다 젤 왼쪽 윗칸을 채우도록 순서를 강제함

  그럼 어떤 칸을 채우려고 할 때, 그 칸보다 왼쪽 윗칸은 다 차있다고 가정할 수 있음

  



            <fig 1>                                          <fig 2>                                           <fig 3>                                          <fig 4>


- 위 그림처럼 현재칸( * )을 채우는 경우의 수는 4가지


4) 계획 검증하기

- 시간복잡도 : 한 칸에서 선택할 수 있는 블럭 모양이 4가지 이므로

                   4 ^ 16(흰칸의 개수가 최대 50개라고 했으니 3개짜리 블럭은 최대 16개를 넣을 수 있음)

                   ≒ 4000 억

                   하지만, 재귀가 4000억을 다 돌지 않음. 그 이유는 한개의 블럭이 결정 되면 다음에 결정될 블럭의 경우의 수는 줄어듬

ex) 2*3 모두 하얀칸인 경우 

    <fig 1>을 선택하면 재귀 1 --- 경우의 수 0

    <fig 2>를 선택하면 재귀 2 --- 경우의 수 1

    <fig 3>을 선택하면 재귀 2 --- 경우의 수 1

    <fig 4>를 선택하면 재귀 0 --- 경우의 수 0

    즉, 실제로 재귀 5번 --- 모든 칸을 채울수 있는 경우의 수는 2

        2개의 블럭을 놓는 이론적인 경우의 수는 4^2 = 16가지

        2개의 블럭을 놓는 경우의 수에서 재귀가 도는 횟수가 많이 줄어듬

        

※ 실제로는 12칸일 경우 재귀는 23번

                 48칸일 경우 재귀는 68655번

※ 줄어드는건 알 수 있지만 그래도 어떻게 저 경우의 수가 시간 내에 들어오리라는 확신을 할 수가 있을까?

   확신을 해야만 브루트 포스로 풀텐데


- 공간복잡도 : global variable : int * 2 + int * 12 * 2 = 104byte

                   local variable : int * 400 = 1600byte(int나, bool 변수들은 무시)

                   즉, 1804byte < 2^16kb


5, 6) 계획 수행하기 및 회고하기

- 솔직히 아직도 재귀가 시간내에 들어오리란 확신을 가지지 못하겠음...

- 4가지 경우의 수를 줄일 때 처음에 '중심'을 가지고 줄였음

  하지만, 다음 중심을 찾기가 너무 어렵고, 중심이 들어가지 않는 경우가 발생한다면 그 부분에서 계속 무한루프를 돌게됨

  알고스팟 예제에서 첫 번째 흰칸을 중심이 들어갈 경우로 판단한다면 아무것도 넣을 수가 없음. 만약 건너뛰게 한다 하더라도

  다음번 시작점을 찾을 때도 (0, 0) 에서 시작하기에 저 부분을 계속 거치게 됨

  그래서 왼쪽 위를 무조건 채운다는 강제를 부여하게 되면 위 그림과 같은 4가지 경우가 생김



소스코드



- 알고리즘 문제 해결전략 1편 중 -

- 저작권 문제시 삭제하겠습니다 -

'먹고살려면 > Algorithm' 카테고리의 다른 글

4편 그래프 : dfs 1  (0) 2017.12.29
3-3편 무식하게 풀기 3  (0) 2017.12.20
번외편 c/c++ 입력속도  (0) 2017.12.12
3-1편 무식하게 풀기 1  (0) 2017.12.11
2편 알고리즘 시간 복잡도 분석  (0) 2017.12.07

+ Recent posts