반응형

https://www.acmicpc.net/problem/1012

 

1012번: 유기농 배추

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

www.acmicpc.net

 

💡 유기농 배추

차세대 영농인 한나는 강원도 고랭지에서 유기농 배추를 재배하기로 하였다. 농약을 쓰지 않고 배추를 재배하려면 배추를 해충으로부터 보호하는 것이 중요하기 때문에, 한나는 해충 방지에 효과적인 배추흰지렁이를 구입하기로 결심한다. 이 지렁이는 배추근처에 서식하며 해충을 잡아 먹음으로써 배추를 보호한다. 특히, 어떤 배추에 배추흰지렁이가 한 마리라도 살고 있으면 이 지렁이는 인접한 다른 배추로 이동할 수 있어, 그 배추들 역시 해충으로부터 보호받을 수 있다. 한 배추의 상하좌우 네 방향에 다른 배추가 위치한 경우에 서로 인접해있는 것이다.
한나가 배추를 재배하는 땅은 고르지 못해서 배추를 군데군데 심어 놓았다. 배추들이 모여있는 곳에는 배추흰지렁이가 한 마리만 있으면 되므로 서로 인접해있는 배추들이 몇 군데에 퍼져있는지 조사하면 총 몇 마리의 지렁이가 필요한지 알 수 있다. 예를 들어 배추밭이 아래와 같이 구성되어 있으면 최소 5마리의 배추흰지렁이가 필요하다. 0은 배추가 심어져 있지 않은 땅이고, 1은 배추가 심어져 있는 땅을 나타낸다.
1100000000
0100000000
0000100000
0000100000
0011000111
0000100111

[입력]
입력의 첫 줄에는 테스트 케이스의 개수 T가 주어진다. 그 다음 줄부터 각각의 테스트 케이스에 대해 첫째 줄에는 배추를 심은 배추밭의 가로길이 M(1 ≤ M ≤ 50)과 세로길이 N(1 ≤ N ≤ 50), 그리고 배추가 심어져 있는 위치의 개수 K(1 ≤ K ≤ 2500)이 주어진다. 그 다음 K줄에는 배추의 위치 X(0 ≤ X ≤ M-1), Y(0 ≤ Y ≤ N-1)가 주어진다. 두 배추의 위치가 같은 경우는 없다.

[출력]
필요한 배추흰지렁이의 개수를 구하라.

 

 

✅ 문제 풀이

 

값이 1이면서 동서남북으로 인접한 1이 존재할 때 한 영역이 되기 때문에, 한 영역안에서는 모든 1이 서로 인접한 1이 존재한다는 것이다. 따라서 어떤 값이 1이면 연쇄적으로 인접한 값을 마주할 때 까지 탐색하여 하나의 영역으로 구할 수 있다. 따라서 이 문제는 DFS로 해결할 수 있다.

 

  1. 먼저 매 테스트 케이스마다 배열에 값을 저장한다. 입력으로 받는 k개의 배추 위치에 대해 1로 저장하고 나머지는 0으로 저장하면 된다.
  2. 배열의 크기만큼 순회하는데, 값이 1이면 첫번 째 영역에 대한 시작이므로, count를 1 증가시킨 후, dfs 함수를 호출한다.
  3. dfs 함수에서는 현재 값이 1인 위치와, arr를 &로 넘겨준다. &로 넘겨주는 이유는 방문한 칸에 대해서는 arr의 값을 수정해주기 위해서이다.
  4. dfs 함수가 호출되면, 현재 인자로 받은 위치의 값을 0으로 바꾸어준다. 그 이유는 방문했음을 나타내기 위함과, 나중에 main의 for문에서 재방문 하지 않게 하기 위함이다.=> 이 문제의 핵심이다.
  5. 그리고 현재의 위치를 기준으로 동서남북 방향에 있는 값이 1인지 확인한다.
  6. 1이라면 같은 영역이므로, 그 칸을 기준으로 dfs 함수를 호출하도록 한다.
  7. 따라서 위의 과정을 반복하다 보면 동일한 영역에 해당하는 값들이 1에서 모두 0으로 바뀌게 되고, main문에서 해당 영역에 해대 시작했던 탐색이 끝나게 되어 하나의 영역을 탐색할 수 있게 되는 것이다.
  8. 위 과정을 거친 후 최종 count 값이 바로 영역의 개수가 되고, 필요한 지렁이의 개수가 된다.

 

☑ 코드 전문
#include<iostream>
#include<vector>

using namespace std;

int dx[] = { -1,1,0,0 };
int dy[] = { 0,0,-1,1 };

void dfs(int x, int y, vector<vector<int>> &arr) {
	arr[x][y] = 0;

	for (int n = 0; n < 4; n++) {
		int r = x + dx[n];
		int c = y + dy[n];
		if (r>=0&&r<arr.size()&&c>=0&&c<arr[0].size()&&arr[r][c] == 1) {
			dfs(r, c, arr);
		}
	}
}
int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);

	int T;//테스트 케이스 개수
	cin >> T;

	for (int i = 0; i < T; i++) {
		int M, N, K;//가로, 세로, 총 배추 개수
		cin >> M >> N >> K;
		vector<vector<int>> arr(N, vector<int>(M, 0));//배추밭

		for (int j = 0; j < K; j++) {
			int x, y;
			cin >> y >> x;
			arr[x][y] = 1;
		}//배추 심기

		int count = 0;//배추흰지렁이의 개수

		for (int j = 0; j < N; j++) {
			for (int k = 0; k < M; k++) {
				if (arr[j][k] == 1) {
					count++;
					dfs(j, k, arr);
				}
			}
		}

		cout << count << "\n";

	}
}

 

 

반응형
반응형

https://www.acmicpc.net/problem/1051

 

1051번: 숫자 정사각형

N×M크기의 직사각형이 있다. 각 칸에는 한 자리 숫자가 적혀 있다. 이 직사각형에서 꼭짓점에 쓰여 있는 수가 모두 같은 가장 큰 정사각형을 찾는 프로그램을 작성하시오. 이때, 정사각형은 행

www.acmicpc.net

 

💡 숫자 정사각형
N×M크기의 직사각형이 있다. 각 칸에는 한 자리 숫자가 적혀 있다. 이 직사각형에서 꼭짓점에 쓰여 있는 수가 모두 같은 가장 큰 정사각형을 찾는 프로그램을 작성하시오. 이때, 정사각형은 행 또는 열에 평행해야 한다.

예제 입력

3 5
42101
22100
22101

출력

9

 

✅ 문제 풀이

주어진 행렬에서 가능한 모든 정사각형을 구해야 함을 알 수 있다. 따라서 이 문제는 무식하게 다 접근하는 브루트포스 알고리즘을 이용해야 한다.

 

  • 먼저 입력의 형태를 보자. 입력으로 들어오는 행렬 값이 공백으로 구분되어 있지않고 붙어있다.
    => 따라서 string으로 받고, 한 문자씩 잘라서 숫자로 바꾸어준 후 벡터에 값을 반영할 것이다.
  • 벡터가 다 채워졌으면, 이제 왼쪽 상단 꼭지점을 기준으로, 배열을 순회할 것이다.
    => 무슨말이냐 하면, 배열의 각 점을 정사각형의 왼쪽 상단 꼭지점으로 생각하고, 정사각형을 찾아보는 것이다.
  • 그런데, 입력을 받을 때 행과 열의 크기를 받았다. 정사각형은 가로와 세로의 길이가 같아야 하기 때문에 행과 열 중에서 더 작은 값이 정사각형의 최대 길이가 될 수 있다.
  • 따라서 행과 열 중 최소의 길이가 1이었다면, 최대 정사각형 길이는 1이기 때문에 크기가 1이다. 
  • 그리고 행과 열 중 최소의 길이가 1이 아니라면 그 값을 m에 저장해 두고, 다음 절차를 통해 최대 길이를 찾아낼 수 있다.
  • 먼저 정사각형의 한변의 길이가 2인 것부터 찾아볼 것이다.
  • 현재 왼쪽 상단 꼭지점의 위치를 (i,j)라고 할 때 길이가 2인 정사각형의 꼭짓점은 (i+1, j) (i,j+1), (i+1, j+1)이 된다.
  • 따라서 k가 1일 때부터 m보다 작을 때까지 정사각형을 키워가면서 조건을 만족하는지 보면 된다.
  • i+k<N이고, j+k<M이면, 해당 정사각형은 행렬안에 유효한 것이다. 따라서 이런 경우에는 (i,j)가 (i+1, j) (i,j+1), (i+1, j+1)각각과 값이 동일한지 비교해주면 된다. 
    => 값이 동일하면, answer의 기존 값과 비교해서 더 큰 값으로 answer를 갱신해주면된다.
  • 참고로 answer는 행렬을 순회하기 전에 1로 초기화 하여 생성해두어야 한다.
  • 모든 순회가 끝난 후 최종 answer값을 제곱한 값을 출력해주면 된다. (문제에서 정사각형의 크기를반환하라고 하였기 때문이다.)

 

전체 코드는 아래와 같다.

#include<iostream>
#include<algorithm>
#include<string>
#include<vector>

using namespace std;

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);

	int N, M;
	cin >> N >> M;

	int m = min(N, M);//작은 값이 정사각형의 한 변의 max가 됨

	vector<vector<int>> rec(N, vector<int>(M, 0));

	for (int i = 0; i < N; i++) {
		string str;
		cin >> str;

		for (int j = 0; j < str.length(); j++) {
			rec[i][j] = str[j]-'0'; //char 문자를 숫자로 바꾸는 함수는 atoi를 쓰지만, string으로 되어 있는 경우엔 인자가 맞지 않으므로,'0'을 뻬주어서 구한다.
		}
	}

	if (m == 1) {
		cout << 1;
		return 0;
	}

	int answer = 1;

	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			for (int k = 1; k < m; k++) {
				if (i + k < N && j + k < M) {//사각형이 범위에 들어오는지 확인
					int t = rec[i][j];//기준이 되는 값을 저장
					if (rec[i][j + k] == t && rec[i + k][j] == t && rec[i + k][j + k] == t) {
						answer = max(k + 1, answer);
					}
				}
			}
		}
	}

	cout << answer * answer;//크기는 변의 제곱

	return 0;
}

 


✏ c++ 문법 알고 넘어가기!
  • 2차원 벡터 선언하기 : vector<vector<int>> vec(행크기, vector<int>(열크기, 초기값));
  • string의 각 문자를 숫자로 변환 : string의 각 문자를 변환할 때는 그냥 str[i]-'0'을 해주면 숫자 값을 얻을 수 있다.
    만약 char로 선언된 문자라면, atoi(문자) 메서드를 사용하면 된다.
    => string의 한 문자를 위 메서드 쓸 수 없는 이유는 인자 형태가 맞지 않아서이다.
반응형
반응형

https://www.acmicpc.net/problem/1158

 

1158번: 요세푸스 문제

첫째 줄에 N과 K가 빈 칸을 사이에 두고 순서대로 주어진다. (1 ≤ K ≤ N ≤ 5,000)

www.acmicpc.net

 

💡 요세푸스 문제
1번부터 N번까지 N명의 사람이 원을 이루면서 앉아있고, 양의 정수 K(≤ N)가 주어진다. 이제 순서대로 K번째 사람을 제거한다. 한 사람이 제거되면 남은 사람들로 이루어진 원을 따라 이 과정을 계속해 나간다. 이 과정은 N명의 사람이 모두 제거될 때까지 계속된다. 원에서 사람들이 제거되는 순서를 (N, K)-요세푸스 순열이라고 한다. 예를 들어 (7, 3)-요세푸스 순열은 <3, 6, 2, 7, 5, 1, 4>이다.

N과 K가 주어지면 (N, K)-요세푸스 순열을 구하는 프로그램을 작성하시오.

 

✅ 문제풀이
  • 간단하게 queue를 이용
  • queue에 1부터 N까지 값을 차례로 넣은 후, 앞에서부터 K-1번 빼서 뒤로 다시 넣는다.
  • 그럼 K번째 값이 queue의 맨 앞에 위치하게 되고, 해당 값을 answer에 넣어주고, queue에서 삭제한다.
  • 위 과정을 queue의 크기가 1이 될때까지 반복한다.
  • queue에 하나의 값만 남게 되면, 그 값을 answer에 넣어준다.
  • 그리고 출력 형식에 맞게, answer에 있는 값을 차례로 출력해주면 된다.

 

아래 그림처럼 동작하게 된다. (예제로 예를 들어보자)

 

1. queue에 1부터 7까지 넣은 모습이다.

 

2. 3번 째 값을 제거하기 위해서 앞에서부터 뒤로 넘겨주어야 한다.

1번 째 값을 queue에서 pop하고, 다시 동일한 queue에 push하여 뒤로 넘어가게 한다.

 

3. 2번 째 값을 queue에서 pop하고, 다시 동일한 queue에 push하여 뒤로 넘어가게 한다.

 

4. 드디어 3(=K)번 째 값에 도달했으니, 이 값은 answer에 넣어주고, queue에서 삭제해준다.

 

5. 위의 과정을 아래 queue의 길이가 1이 될 때까지(=마지막 하나만 남을때까지) 반복해주면 된다.

 

 

최종 코드는 아래와 같다.

#include<iostream>
#include<queue>

using namespace std;

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);

	int N, K;

	cin >> N >> K;

	queue<int> q;
	queue<int> answer;

	for (int i = 1; i <= N; i++) {
		q.push(i);
	}

	while (q.size() > 1) {
		for (int i = 1; i < K; i++) {
			int temp = q.front();
			q.pop();
			q.push(temp);
		}
		answer.push(q.front());//k번 째 빼기
		q.pop();
	}

	answer.push(q.front());
	q.pop();

	cout << "<"<<answer.front();
	answer.pop();
	while (!answer.empty()) {
		cout << ", " << answer.front();
		answer.pop();
	}
	cout << ">";

}
반응형
반응형

코테를 보고나서 DFS의 중요성을 뼈저리게 느끼고, 한 번 더 개념을 잡고, 흐름을 잡고자 풀어본 문제이다.

 

✅ 코테에서 머뭇거렸던 부분

  • DFS함수를 어느 시점에서 불러야 할지
  • DFS함수를 어떻게 구성해야 할지
    (함수 내에서 재귀적으로 호출하는 부분은 어떻게?)
    (해당 노드를 방문할지 말지를 어떻게?)
  • 방문하고 나서 다시 이전 단계로 돌아와 다른 경로를 찾게 하려면 코드를 어떻게?⭐⭐⭐(이게 관건임)

 

위와 같은 이유들은 내가 dfs를 스택으로 해결한 문제만 풀어봤기 때문이고, dfs함수를 써서 재귀적으로 함수를 호출하며 방문 여부를 체크하는 배열을 사용한 문제를 접해보지 못했기 때문에, 그 로직을 정확히 이해하지 못한 것 같다.

 

이 문제를 계기로 dfs의 전체적인 흐름을 바로잡고자 한다.

 

 

💡 문제
두 개의 단어 begin, target과 단어의 집합 words가 있습니다. 아래와 같은 규칙을 이용하여 begin에서 target으로 변환하는 가장 짧은 변환 과정을 찾으려고 합니다.

1. 한 번에 한 개의 알파벳만 바꿀 수 있습니다.
2. words에 있는 단어로만 변환할 수 있습니다.

예를 들어 begin이 "hit", target가 "cog", words가 ["hot","dot","dog","lot","log","cog"]라면 "hit" -> "hot" -> "dot" -> "dog" -> "cog"와 같이 4단계를 거쳐 변환할 수 있습니다.
두 개의 단어 begin, target과 단어의 집합 words가 매개변수로 주어질 때, 최소 몇 단계의 과정을 거쳐 begin을 target으로 변환할 수 있는지 return 하도록 solution 함수를 작성해주세요.


변환할 수 없는 경우에는 0를 return 합니다.

 

다음과 같은 것을 고려해 볼 수 있다.

  1. 현재 begin과 비교했을 때 words 중에 딱 한 문자만 다른 단어가 있는지?
    => 이를 위한 함수가 필요하다.
  2. 만약 한문자만 다른 단어가 있으면 그 단어에서 다음 변경될 단어를 찾을 때 역시 한 문자만 다른지를 확인해야하고, 그 문자를 방문한 이력이 있는지를 확인해야한다.
    =>해당 단어를 방문한 이력이 있는지를 기록하는 boolean타입의 배열이 필요하다.
  3. 조건에 맞는 단어를 방문하고 나서 다음 방문 여부를 확인하고 이어서 또 방문하기 위해선 dfs함수안에 dfs함수를 재귀적으로 호출하여 해당 루트에 대해 끝까지 방문하도록 해야한다.
  4. 재귀함수이더라도 끝은 있어야 한다. dfs함수 내에 if문으로, 현재 방문한 단어가 target과 같을 시에는 answer를 갱신하고 dfs를 빠져나오도록 한다.
  5. 항상 dfs를 재귀로 호출한 다음에는, 이전 단계로 돌아왔을 때 다른 루트를 고려하기 위해서 해당 노드의 방문여부를 다시 false로 바꾸어주는 단계가 필요하다.(=이것은 즉, 이 노드를 방문하지 않았다면?과 같은 의미이다=>이어지는 다음 루프에서는 해당 노드를 방문하지 않은채로 고려할 수 있기 때문이다⭐⭐⭐)
✏ [5에 대한 부가 설명]

1,2,3 노드가 있다고 하자.
현재 1번 노드를 방문한 상태이고, 앞으로 방문기록이 없는 2와 3에 대해 방문을 할것이다.
for문을 통해 번호순으로 방문할 것이기 때문에, 2를 먼저 방문한다.
2를 방문했으므로 visited배열에 2를 방문했다는 표시(true)를 한다.
그리고 다시 2를 시작으로 남은 노드를 순차적으로 방문한다. 
현재 예시에서는 방문기록이 없는것 중 남은게 3뿐이므로 3을 방문한다.
더이상 방문할 곳이 없기 때문에 다시 이전 단계로 돌아가 본다.
2를 다시 방문하지 않은 상태로 둔다.
하지만 이전 for루프에서는 순차적으로 2를 방문한 것이었고, 이번 for루프에서는 3을 방문할 차례이다.
따라서 3을 방문하고, visited배열에 3을 방문했다는 표시를 한다.
그리고 다시 3을 시작으로 남은 노드를 순차적으로 방문한다.
현재 방문기록이 없는게 2뿐이므로 2를 방문한다.

이렇게 되면 1->2->3으로 한번 방문했고, 1->3->2로도 한번 방문했다.
이런식으로 첫 시작이 잡히면 그 뒤로 방문처리, 재귀적으로 호출, 다시 미방문처리, 다음루프 로 이어지면서 모든 경로를 탐색해 볼 수 있게 되는 것이다.

 

위와 같은 사항들을 고려하면서 코드를 작성하면 다음과 같은 단계로 작성할 수 있다.

 

✅ 코드 작성 단계

1. 간단한 예외 처리해주기.
   - 문제에서 주어진 예시를 보면 words배열에 target이 없는 경우 변환될 수 없는 것이기 때문에, 0을 answer로 리턴하도록 되어 있다.

   - 배열에 해당 요소가 있는지를 비교하면되는데, 이는 ArrayList의 contains() 메서드를 활용하면 매우 쉽다.

list = new ArrayList<>(Arrays.asList(words));//리스트에 Arrays.asList메서드를 통해
//words배열을 리스트로 변경하고 있다
        
if(!list.contains(target)) return 0;//만약 list에서 target이 없으면 0을 리턴

   -list의 경우 List<String> list 로 static 전역으로 선언하여 사용하였다.

 

2. solution함수 내에서 첫 시작 방문을 for문으로 돌기

   - 어떤 노드가 시작이 될지 모르기 때문에, 시작을 정해주기 위한 모든 경우의 수를 고려해야한다.

   - 따라서 for문을 words의 크기만큼 돌면서 현재 단어가 begin과 한글자만 차이나는지 확인해야 한다.

   - 위를 확인하기 위한 boolean타입의 함수를 생성해주어야 한다.

for(int i=0; i<words.length; i++){//모든 워드에 대해 시작을 탐색
//???

 

2-1. canChange함수 정의하기

   - 현재 begin 단어가 words의 해당 단어와 한글자만 차이나면 true를, 아니면 false를 반환하도록 하는 함수이다.

   - boolean을 반환한다.

   - for문을 돌면서 begin과 target의 한글자 한글자가 같은지 비교하고, 다르면 count한다.

   - count가 1이면 true를 아니면 false를 반환한다.

public boolean canChange(String target, String begin){//begin과 target을 인자로 받는다
        int count=0;//count는 0으로 초기화한다
        for(int i=0; i<begin.length(); i++){//begin글자수만큼 비교
            if(begin.charAt(i)!=target.charAt(i)) count++;//다르면 카운트
        }
        
        return count==1;//카운트가 1이면 한글자만 차이나는 것이므로 후보가 된다
    }

 

2-2. 한글자만 차이나는 모든 단어에 대해 해당 단어를 시작으로 하는 루트를 모두 탐색하기

   - 이제 2에서 설명한 for문에서 words 중에 현재 단어가 canChange를 만족하면, visited[] 배열을 새로 할당한다.

   - 해당 단어의 인덱스를 통해 visited에 방문했음을 표시한다.

   - DFS함수를 호출해서 현재 단어를 시작으로 아직 방문하지 않은 나머지 단어에 대해 위 과정을 거치도록 한다.

   - DFS함수를 구현해야 한다.

for(int i=0; i<words.length; i++){
            if(canChange(words[i], begin)){
                visited = new boolean[words.length];
                visited[i]=true;
                dfs(????);
            }
}

 

3. DFS함수 구현하기

   - dfs함수에서는 사실상 solution함수에 있는 것을 반복하는 것이라고 보면 되는데, 재귀적으로 호출할 것이기 때문에, 마지막에는 멈출 수 있는 조건이 항상 있어야 한다.

   - dfs함수에 현재 루트에서 몇번 노드를 탐색했는지(=answer와 직결됨), 현재 방문한 단어는 무엇인지, 최종 찾고자 하는 (=도달하고자 하는)단어는 무엇인지에 대해 인자로써 알려주어야 한다.

   - 따라서 몇번 노드를 탐색했는지는 int타입의 index, 현재 방문한 단어는 String의 begin, 찾고자 하는 단어는 String의 target이다. 

   - dfs에서는 일단 현재 방문한 노드 begin이 target과 동일한지 비교하고, 동일하면 answer를 갱신한다.

   - 이때 answer는 몇번 노드를 탐색했는지를 나타내는 index와 현재 answer중에 더 작은 것으로 선택하여 갱신하도록 한다. 그리고 return을 하여 dfs가 끝나도록 한다

   - 만약 같지 않다면, for문을 통해 다음 방문할 노드를 찾기 위해 words를 또한번 탐색하는데, visited와 canChange를 통해, 방문한 기록이 없고, 한글자 차이인 경우에는 그 단어를 방문한 상태로 바꿔준다.

   - 그리고 dfs를 호출해서 현재 막 방문한 상태로 바꿔준 단어를 기점으로 위 단계를 반복하도록 한다.

   - 만약 다 돌아서 이전 단계로 돌아왔을 때에는 다시 방문하지 않은 상태로 바꾸어주고, 다음 루프에서 다른 단어를 먼저 방문하더라도 이 노드가 방문될 수 있도록 (즉 여러 루트를 고려하도록 하기 위해, 위에 5번 설명 참고)한다.

   - 위 단계가 매우 중요하다. 이것이 없으면 다시 돌아가서 다른 루트를 찾는 과정을 거칠 수가 없기 때문이다.

public void dfs(int index, String[] words, String begin, String target){
        if(begin.equals(target)){
            answer=Math.min(index, answer);
            return;//이에 해당하면 아래를 실행하지 않기 위해
        }
        
        for(int i=0; i<words.length; i++){
            if(!visited[i]&&canChange(words[i],begin)){
                visited[i]=true;
                dfs(index+1, words, words[i], target);//재귀호출하여 현재 루트를 이어가도록한다
                visited[i]=false;//다른 루트를 탐색하도록 하기 위함이다.매우 중요!!!
            }
        }
    }

 

4. DFS함수 호출하고, 최종 answer 리턴하기.

   - 앞에서 정의한 dfs에 따라서 인자를 다음과 같이 설정해준다.

   - 첫 방문 노드의 경우 한번 방문했으므로 index는 1이된다. 그리고 방문했을 경우 begin은 words[i]가 되는 것이고, target은 최종 target이다.

for(int i=0; i<words.length; i++){
            if(canChange(words[i], begin)){
                visited = new boolean[words.length];
                visited[i]=true;
                dfs(1,words,words[i],target);
            }
        }
        
        return answer;

   - 이렇게 다 하고 나면 answer에는 최종 답이 들어간다.

 

5. 세부사항

   - min 연산을 위해 answer는 integer의 max_value로 초기화 하였다.

   - answer, visited배열, list는 static 전역으로 선언하였다.

   - answer는 그래서 모든 연산에서 실시간으로 제일 작은 값을 얻도록 하였다.

 

 

최종코드이다.

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

class Solution {
    static List<String> list;
    static int answer;
    static boolean[] visited;
    
    public int solution(String begin, String target, String[] words) {
        answer = Integer.MAX_VALUE;
        list = new ArrayList<>(Arrays.asList(words));
        
        if(!list.contains(target)) return 0;
        
        for(int i=0; i<words.length; i++){
            if(canChange(words[i], begin)){
                visited = new boolean[words.length];
                visited[i]=true;
                dfs(1,words,words[i],target);
            }
        }
        
        return answer;
    }
    public void dfs(int index, String[] words, String begin, String target){
        if(begin.equals(target)){
            answer=Math.min(index, answer);
            return;
        }
        
        for(int i=0; i<words.length; i++){
            if(!visited[i]&&canChange(words[i],begin)){
                visited[i]=true;
                dfs(index+1, words, words[i], target);
                visited[i]=false;
            }
        }
    }
    
    public boolean canChange(String target, String begin){
        int count=0;
        for(int i=0; i<begin.length(); i++){
            if(begin.charAt(i)!=target.charAt(i)) count++;
        }
        
        return count==1;
    }
}
반응형

+ Recent posts