m,n,h값을 통해 3차원 벡터를 초기화 해주고 1인 부분을 queue에 저장하고 이를 BFS방식으로 순회하면서 1인 부분을 추가하고 이 추가한 값을 다시 queue에 넣어서 날마다 반복해주면 된다. 전체 개수와 익은 개수를 비교하기 위해 빈것도 포함해서 개수를 추가해줬다.
정답코드
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
// 6방향 이동 (위, 아래, 좌, 우, 앞, 뒤)
int dx[6] = { 0, 0, 0, 0, -1, 1 };
int dy[6] = { 0, 0, -1, 1, 0, 0 };
int dz[6] = { -1, 1, 0, 0, 0, 0 };
int main() {
int m, n, h;
cin >> m >> n >> h;
vector<vector<vector<int>>> tomato(h, vector<vector<int>>(n, vector<int>(m)));
queue<pair<int, pair<int, int>>> q; // 큐에 (z, x, y) 좌표 저장
int empty_count = 0; // 비어 있는 칸 개수
// 입력 받기
for (int z = 0; z < h; z++) {
for (int x = 0; x < n; x++) {
for (int y = 0; y < m; y++) {
cin >> tomato[z][x][y];
if (tomato[z][x][y] == 1) {
q.push({ z, {x, y} }); // 익은 토마토 위치 큐에 삽입
}
else if (tomato[z][x][y] == -1) {
empty_count++; // 비어 있는 칸 카운트
}
}
}
}
int total_cells = n * m * h - empty_count; // 전체 칸에서 비어 있는 칸 제외
int ripe_count = q.size(); // 초기 익은 토마토 개수
int days = -1;
// 이미 모든 토마토가 익어 있는 경우
if (ripe_count == total_cells) {
cout << 0 << '\n';
return 0;
}
// BFS 수행
while (!q.empty()) {
int size = q.size();
for (int i = 0; i < size; i++) {
int z = q.front().first;
int x = q.front().second.first;
int y = q.front().second.second;
q.pop();
for (int d = 0; d < 6; d++) {
int nz = z + dz[d];
int nx = x + dx[d];
int ny = y + dy[d];
// 배열 범위 체크 및 익지 않은 토마토 찾아서 익히기
if (nz >= 0 && nz < h && nx >= 0 && nx < n && ny >= 0 && ny < m && tomato[nz][nx][ny] == 0) {
tomato[nz][nx][ny] = 1; // 익은 토마토로 상태 변경
q.push({ nz, {nx, ny} }); // 큐에 추가
ripe_count++; // 익은 토마토 수 증가
}
}
}
days++; // 하루가 지나면
}
// 모든 칸이 익었는지 확인
if (ripe_count == total_cells) {
cout << days << '\n'; // 모든 토마토가 익었으면 소요된 일수 출력
}
else {
cout << -1 << '\n'; // 익지 않은 토마토가 남았으면 -1 출력
}
return 0;
}
2차원 벡터를 통해 토마토가 있는 곳을 입력받고 출발점이 되는 1을 모두 큐에 저장하고 이 q를 BFS로 순회하면서 토마토가 있는 곳을 익게하고 이 익은 토마토가 다시 출발점이 되어서 이 큐가 빌때까지 계속하면 된다.
전체가 다 익었는지 확인하기 위하여 비어있는 토마토의 개수도 같이 세어준다.
정답코드
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int dx[4] = { 0,0,-1,1 };
int dy[4] = { -1,1,0,0 };
int main()
{
int m, n;
cin >> m >> n;
vector<vector<int>> tomato(n, vector<int>(m));
queue<pair<int, int>> q; //출발점 큐
int empty_count = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> tomato[i][j];
if (tomato[i][j] == 1) {
q.push({ i, j }); // 익은 토마토의 위치 저장
}
else if (tomato[i][j] == -1) {
empty_count++; // 비어있는 칸 개수 카운트
}
}
}
int days = -1;
int total_cells = n * m;
int ripe_count = q.size() + empty_count; // 초기 익은 토마토와 비어있는 칸
while (!q.empty())
{
int size = q.size();
for (int i = 0; i < size; i++)
{
int x = q.front().first;
int y = q.front().second;
q.pop();
for (int d = 0; d < 4; d++)
{
int nx = x + dx[d];
int ny = y + dy[d];
if (nx >= 0 && nx < n && ny >= 0 && ny < m && tomato[nx][ny] == 0)
{
tomato[nx][ny] = 1;
q.push({ nx,ny });
ripe_count++;
}
}
}
days++;
}
// 모든 칸이 익었는지 확인
if (ripe_count == total_cells) {
cout << days << '\n';
}
else {
cout << -1 << '\n';
} return 0;
return 0;
}
이전에 만들었던 대화 출력은 올바르게 되었으니 이제 대화창에서 선택지가 출력되고 이를 선택할 수 있게 만들어주자.
일단 저번에 만들었던 대화를 출력해주는 DialogueManager의 ContinueStory 함수를 수정해주자.
DialogueManager.cs
public void ContinueStory()
{
if (currentStory == null) // Null 체크 추가
{
Debug.LogError("currentStory가 null입니다!");
return;
}
if (currentStory.canContinue) // 더 보여줄 이야기가 있다면
{
popup.displayNameText.text = npcdata.getName();
popup.portraitImage.sprite = npcdata.getPortrait();
popup.dialogueText.text = currentStory.Continue(); // 한줄 출력
DisplayChoices(); // 선택이 있으면 선택 출력
}
else
{
ExitDialogueMode();
}
}
오류체크와 선택이 있다면 선택을 출력해주는 함수를 추가해줬다.
이 Display함수는 만약 선택이 있다면 선택의 개수만큼만 버튼을 활성화 시켜주고 나머지는 비활성화시켜준다. 그리고 마지막에 코루틴을 사용하여 첫 항목이 선택되게 한다. 이 코루틴이 있어야 선택이 정상적으로 작동한다.
DialogueManager.cs
private void DisplayChoices()
{
if (popup == null) // Null 체크 추가
{
Debug.LogError("팝업 UI가 null입니다!");
return;
}
List<Choice> currentChoices = currentStory.currentChoices;
if (currentChoices.Count > popup.choices.Length) // 현재 선택지의 개수가 버튼의 개수보다 많으면 오류
{
Debug.LogError("More choices than ever");
}
int index = 0;
foreach (Choice choice in currentChoices)
{
popup.choices[index].gameObject.SetActive(true);
popup.choicesText[index].text = choice.text;
index++;
}
for (int i = index; i < popup.choices.Length; i++)
{
popup.choices[i].gameObject.SetActive(false);
}
popup.choicep.SetActive(true);
StartCoroutine(SelectFirstChoice());
}
그리고 버튼에 OnclickEvent를 추가해주기 위해 MakeChoice함수를 추가하고 이를 Popup을 관리해주는 객체에서 사용하도록 하자.
DialogueManager.cs
public void makeChoice(int choice)
{
if (currentStory == null) // Null 체크 추가
{
Debug.LogError("currentStory가 null입니다!");
return;
}
currentStory.ChooseChoiceIndex(choice);
ContinueStory();
}
UI_DialioguePopup.cs
private void Start()
{
for (int i = 0; i < choices.Length; i++)
{
int id = i;
choiceButton[i].onClick.AddListener(() => Managers.Dialogue.makeChoice(id));
}
}
이렇게 해주면 이제 대화를 진행하면서 선택지가 있으면 선택지를 선택할 수 있게 된다.
이제 다음에는 이 선택지에 따라 퀘스트가 진행되게 만들어볼 것이다.
※매니저에서 코루틴을 사용하는 상황에서 만약 각 매니저가 통합매니저에서 싱글톤으로 관리되고 있다고 하면 사용할 때 New 키워드를 사용하면 nullreferenceexception 에러가 뜬다. 이를 방지하기 위해 GameObject에서 Getcomponent를 통해 해당 매니저를 가져와서 사용해야한다.
DFS를 루트노드 1에서 제일 먼 노드를 찾고 그 노드에서 제일 먼 거리를 찾아서 그 거리를 출력해주면 된다.
정답코드
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int MAX = 100001; // 최대 노드 수
vector<pair<int, int>> tree[MAX]; // 트리를 저장할 인접 리스트 (노드 번호, 거리)
bool visited[MAX]; // 방문 여부를 저장
int maxDistance; // 트리의 지름
int farthestNode; // 가장 먼 노드
void dfs(int node, int distance) {
visited[node] = true;
// 최대 거리 갱신
if (distance > maxDistance) {
maxDistance = distance;
farthestNode = node;
}
// 연결된 노드 방문
for (auto next : tree[node]) {
int nextNode = next.first;
int nextDistance = next.second;
if (!visited[nextNode]) {
dfs(nextNode, distance + nextDistance);
}
}
}
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
int node;
cin >> node;
while (true)
{
int Node, distance;
cin >> Node;
if (Node == -1) break;
cin >> distance;
tree[node].push_back({ Node,distance });
}
}
memset(visited, false, sizeof(visited));
maxDistance = 0;
dfs(1, 0); // 임의의 노드(1번)에서 시작
// 두 번째 DFS 실행
memset(visited, false, sizeof(visited));
maxDistance = 0;
dfs(farthestNode, 0); // 첫 번째 DFS에서 가장 먼 노드를 시작점으로 설정
// 트리의 지름 출력
cout << maxDistance << endl;
return 0;
}
만약 1에 6과 4가 연결되어 있다면 1은 루트노드이기 때문에 6와 4의 부모는 1이되는것이다.
정답코드
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int main()
{
int n;
cin >> n;
vector<vector<int>> tree(n + 1);
vector<int>parent(n + 1, 0);
for (int i = 0; i < n - 1; i++)
{
int u, v;
cin >> u >> v;
tree[u].push_back(v);
tree[v].push_back(u);
}
//BFS
queue<int> q;
q.push(1);
parent[1] = -1; //루트노드는 부모x
while (!q.empty())
{
int current = q.front();
q.pop();
for (int next : tree[current]) {
if (parent[next] == 0) { // 아직 방문하지 않은 노드
parent[next] = current; // 부모 기록
q.push(next); // 큐에 추가
}
}
}
// 결과 출력 (2번 노드부터 N번 노드까지의 부모 출력)
for (int i = 2; i <= n; i++) {
cout << parent[i] << '\n';
}
return 0;
}