Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions kkshyun/week3/문제1_BOJ1182_풀이.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import java.io.*;

public class Main {
public static int S;
public static int N;
public static int count = 0;
public static int[] arr;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String[] s = br.readLine().split(" ");
N = Integer.parseInt(s[0]);
S = Integer.parseInt(s[1]);
arr = new int[N];
s = br.readLine().split(" ");
for (int i = 0; i < N; i++) {
arr[i] = Integer.parseInt(s[i]);
}
dfs(0,0);
if(S == 0) count--;
bw.write(count+"\n");
bw.flush();
bw.close();
}
public static void dfs(int depth, int sum) {
if(depth == N) {
if(sum == S)
count++;
return;
}
dfs(depth+1, sum + arr[depth]);
dfs(depth+1, sum);
}
}
70 changes: 70 additions & 0 deletions kkshyun/week3/문제1_BOJ1182_풀이방식.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
## BOJ 1182 문제 요약

- 정수 수열(길이 N)과 목표 합 S가 주어질 때, 원소를 1개 이상 선택해 만든 부분수열의 합이 S가 되는 경우의 수를 구하는 문제

---

## 아이디어

- 모든 원소에 대해 선택/비선택 두 가지를 시도하는 완전 탐색(DFS/백트래킹)
- 재귀로 인덱스(depth)를 하나씩 늘리며 현재 합(sum) 누적
- 끝까지 탐색: depth == N까지 도달했을 때만 합을 판정해 정확한 경우의 수 세도록 함
- 공집합(아무것도 선택 X)은 제외해야 하므로 S = 0이면 결과에서 1회 빼줌 (공집합 케이스 제거)

---

## 알고리즘 단계

1. dfs(depth, sum) 돌림
- depth == N이면 sum == S인지 확인 → 같으면 count++ 하고 리턴
- 현재 원소 선택 → dfs(depth+1, sum + arr[depth])
- 현재 원소 비선택 → dfs(depth+1, sum)
2. 모든 탐색 끝나면 S == 0일 때 공집합 제외 위해 count--
3. count 출력

---

## 코드

```java
import java.io.*;

public class Main {
public static int S;
public static int N;
public static int count = 0;
public static int[] arr;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String[] s = br.readLine().split(" ");
N = Integer.parseInt(s[0]);
S = Integer.parseInt(s[1]);
arr = new int[N];
s = br.readLine().split(" ");
for (int i = 0; i < N; i++) {
arr[i] = Integer.parseInt(s[i]);
}
dfs(0,0);
if(S == 0) count--;
bw.write(count+"\n");
bw.flush();
bw.close();
}
public static void dfs(int depth, int sum) {
if(depth == N) {
if(sum == S)
count++;
return;
}
dfs(depth+1, sum + arr[depth]);
dfs(depth+1, sum);
}
}
```

---

## 시간 복잡도

- 메모리: 15864 KB, 시간: 136 ms
68 changes: 68 additions & 0 deletions kkshyun/week3/문제2_BOJ2580_풀이.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import java.io.*;

public class Main {
static int[][] graph;
static int length;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
length = 9;
String[] s;
graph = new int[length][length];
for (int i = 0; i < length; i++) {
s = br.readLine().split(" ");
for (int j = 0; j < length; j++) {
graph[i][j] = Integer.parseInt(s[j]);
}
}

dfs(0,0);

for (int i = 0; i < length; i++) {
for (int j = 0; j < length; j++) {
bw.write(graph[i][j] + " ");
}
bw.write("\n");
}
bw.flush();
bw.close();
}

public static boolean dfs(int row, int col) {
if (row == length) return true; // 모든 행 채움
int nextRow = (col == length - 1) ? row + 1 : row;
int nextCol = (col == length - 1) ? 0 : col + 1;
if(graph[row][col] != 0)
return dfs(nextRow, nextCol);
for (int i = 1; i <= 9; i++) {
if(possible(row, col, i)) {
graph[row][col] = i;
if (dfs(nextRow, nextCol)) return true; // 해답 찾으면 즉시 종료
graph[row][col] = 0;
}
}
return false;
}

public static boolean possible(int row, int col, int target) {
// 겹치는 열 원소가 있는지 확인
for (int i = 0; i < length; i++) {
if(graph[row][i] == target) return false;
}

// 겹치는 행 원소가 있는지 확인
for (int i = 0; i < length; i++) {
if(graph[i][col] == target) return false;
}

// 네모칸에 들어갈 수 있는지 확인
int recRow = row - row%3;
int recCol = col - col%3;
for (int i = recRow; i < recRow+3; i++) {
for (int j = recCol; j < recCol+3; j++) {
if(graph[i][j] == target) return false;
}
}
return true;
}
}
115 changes: 115 additions & 0 deletions kkshyun/week3/문제2_BOJ2580_풀이방식.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
## BOJ 2580 문제 요약

- 9×9 스도쿠 보드에서 0으로 표시된 빈칸을 1~9로 채워, 같은 행/열/3×3 박스에 중복 숫자가 없도록 스도쿠 완성
- 항상 해답이 존재하며, 하나의 해답만 출력

---

## 아이디어

- 완전 탐색 + 백트래킹(DFS)
- (row, col)을 좌→우 → 다음 행 순서로 진행하며 모든 칸을 순회
- row == 9면 모든 칸을 채운 것이므로 성공(true)을 반환
- 미리 채워진 칸(0이 아닌 칸)은 다음 칸으로 진행
- 빈칸(0)이면 1부터 9를 순서대로 시도:
- 제약 검사 possible(row, col, n)
- 같은 행/열/3×3 박스에 n이 이미 있으면 불가
- 가능하면 값을 넣고 다음 칸 재귀 호출
- 재귀가 실패하면 0으로 복구하고 다음 숫자 시도
- 한 칸에서 가능한 모든 숫자가 실패하면 false를 반환해 상위로 실패 전파
- 어디서든 해답을 찾으면 true를 상위로 즉시 전파해 전체 탐색을 종료

---

## 알고리즘 단계

1. 입력을 받아 graph[9][9]에 저장
2. dfs(0, 0) 호출
- 현재 칸이 이미 채워짐 → 다음 칸으로 진행
- 현재 칸이 빈칸(0) → 1부터 9 순회
- possible(row, col, n)로 제약 검사
- 가능하면 배치 후 dfs(nextRow, nextCol)
- 실패 시 원복(graph[row][col] = 0)
1. dfs가 true를 반환하면 보드는 완성 상태 → 출력

---

## 코드

```java
import java.io.*;

public class Main {
static int[][] graph;
static int length;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
length = 9;
String[] s;
graph = new int[length][length];
for (int i = 0; i < length; i++) {
s = br.readLine().split(" ");
for (int j = 0; j < length; j++) {
graph[i][j] = Integer.parseInt(s[j]);
}
}

dfs(0,0);

for (int i = 0; i < length; i++) {
for (int j = 0; j < length; j++) {
bw.write(graph[i][j] + " ");
}
bw.write("\n");
}
bw.flush();
bw.close();
}

public static boolean dfs(int row, int col) {
if (row == length) return true; // 모든 행 채움
int nextRow = (col == length - 1) ? row + 1 : row;
int nextCol = (col == length - 1) ? 0 : col + 1;
if(graph[row][col] != 0)
return dfs(nextRow, nextCol);
for (int i = 1; i <= 9; i++) {
if(possible(row, col, i)) {
graph[row][col] = i;
if (dfs(nextRow, nextCol)) return true; // 해답 찾으면 즉시 종료
graph[row][col] = 0;
}
}
return false;
}

public static boolean possible(int row, int col, int target) {
// 겹치는 열 원소가 있는지 확인
for (int i = 0; i < length; i++) {
if(graph[row][i] == target) return false;
}

// 겹치는 행 원소가 있는지 확인
for (int i = 0; i < length; i++) {
if(graph[i][col] == target) return false;
}

// 네모칸에 들어갈 수 있는지 확인
int recRow = row - row%3;
int recCol = col - col%3;
for (int i = recRow; i < recRow+3; i++) {
for (int j = recCol; j < recCol+3; j++) {
if(graph[i][j] == target) return false;
}
}
return true;
}
}

```

---

## 시간 복잡도

- 메모리: 23968 KB, 시간: 460 ms
30 changes: 30 additions & 0 deletions kkshyun/week3/알고리즘정리(백트래킹).md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
## 백트래킹

### 01. “백트래킹” 이란?

- 재귀적으로 선택을 진행하다가 조건을 만족하지 못하는 분기(막다른 길)에 도달하면 이전 상태로 되돌아가(undo) 다른 선택지를 시도하는 탐색 기법
- 핵심 동작
- 재귀 호출 전: 상태 변경(선택)
- 재귀 호출 후: 상태 복원(되돌리기) → 다른 경로 탐색 가능

### 02. 언제 필요한가?

- 백트래킹 불필요
- 그래프 구조/연결 확인 (예: 연결 요소 개수, 도달 가능 여부)
- 노드를 한 번씩만 방문하면 되는 문제
- 백트래킹 필요
- 조건을 만족하는 특정 경로 탐색 (예: 길이·비용 제한 있는 경로)
- 가능한 모든 경우의 수 탐색 (순열, 조합, 부분집합, N-Queens, TSP 등)
- 탐색 중간에 가지치기(pruning) 로 불필요한 분기 조기 차단

### 03. 구현방법

```java
for (int node : A[n]) {
if (!visited[node]) { // 아직 이 경로에서 방문 안 한 노드만
visited[node] = true; // 선택
DFS(depth + 1, node); // 진행
visited[node] = false; // 백트래킹: 되돌리기
}
}
```