해결된 질문
작성
·
236
0
http://boj.kr/abd4a896e8f8492ebcc55792822142f0
먼저 입력을 받으며 ice라는 큐에 얼음의 위치를 전부 담고
bfs_swan으로 백조가 서로 만날 수 있는 지 확인합니다.
그 후에 melt_ice라는 함수로 ice에 들어있는 큐를 이용해서 얼음을 녹이며 녹지 않은 얼음을 ice에 담고 check_swan 함수를 이용해서 한쪽 백조의 위치 주변에 녹은 얼음을 시작점으로 하여 다른쪽의 백조에 닿을 수 있는 지 bfs로 탐색합니다.(이 때 백조의 visited배열은 초기화를 해주지 않습니다.) 이렇게 melt_ice, check_swan 을 계속 반복해주며 로직을 반복하는데 어느 부분에서 시간초과가 나는 지 잘 모르겠습니다. 감사합니다!!
답변 2
0
안녕하세요 02님 ㅎㅎ
시간초과가 일어나는 부분, 불필요한 부분은 다음과 같습니다.
void bfs_swan(int y, int x)
{
int ny, nx;
매번 초기 시작점에서부터 BFS가 불필요하게 일어납니다.
melt_ice : 괜찮습니다.
check_swan : 괜찮습니다.
감사합니다.
안녕하세요 02님 ㅎㅎ
아 제가 착각을 했는데요. 저게 매번 일어나는 거 같았는데 매번 안 일어나네요.
다만 불필요한 부분은 다음과 같습니다.
#include <bits/stdc++.h>
using namespace std;
int arr[1504][1504], visited[1504][1504];
int dy[] = {-1, 0, 1, 0};
int dx[] = {0, 1, 0, -1};
queue<pair<int, int>>ice;
queue<pair<int, int>>position;
vector<pair<int, int>>swan;
string str;
int r, c, cnt, sw;
void melt_ice()
{
int x, y, nx, ny, qsize, flag;
qsize = ice.size();
queue<pair<int, int>>q;
for (int i = 0; i < qsize; i++)
{
tie(y, x) = ice.front();
ice.pop();
flag = 0;
for (int i = 0; i < 4; i++)
{
ny = y + dy[i];
nx = x + dx[i];
if (ny >= r || ny < 0 || nx >= c || nx < 0) continue;
if (arr[ny][nx] == 0)
{
flag = 1;
q.push({y, x});
visited[y][x] = 0;
break ;
}
}
if (flag == 0)
ice.push({y, x});
}
while (q.size())
{
tie(y, x) = q.front();
q.pop();
arr[y][x] = 0;
}
}
void bfs_swan(int y, int x)
{
int ny, nx;
queue<pair<int, int>> q;
visited[y][x] = 1;
q.push({y, x});
while(q.size())
{
tie(y, x) = q.front();
q.pop();
for (int i = 0; i < 4; i++)
{
ny = y + dy[i];
nx = x + dx[i];
if (ny >= r || ny < 0 || nx >= c || nx < 0 || visited[ny][nx]) continue;
visited[ny][nx] = 1;
if (arr[ny][nx] == -1)
{
position.push({ny, nx});
continue;
}
q.push({ny, nx});
if (visited[swan[1].first][swan[1].second])
{
sw = 1;
return;
}
}
}
}
void check_swan()
{
int x, y, nx, ny, psize, idx;
queue<pair<int, int>> q;
psize = position.size();
idx = 0;
while (idx < psize)
{
tie(y, x) = position.front();
position.pop();
q.push({y, x});
visited[y][x] = 1;
while (q.size())
{
tie(y, x) = q.front();
q.pop();
for (int i = 0; i < 4; i++)
{
ny = y + dy[i];
nx = x + dx[i];
if (ny >= r || ny < 0 || nx >= c || nx < 0 || visited[ny][nx]) continue;
visited[ny][nx] = 1;
if (arr[ny][nx] == -1)
{
position.push({ny, nx});
continue;
}
q.push({ny, nx});
if (visited[swan[1].first][swan[1].second])
{
sw = 1;
return;
}
}
}
idx++;
}
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
cin >> r >> c;
for (int i = 0; i < r; i++)
{
cin >> str;
for (int j = 0; j < str.length(); j++)
{
if (str[j] == '.')
{
arr[i][j] = 0;
}
else if (str[j] == 'X')
{
arr[i][j] = -1;
ice.push({i, j});
}
else
{
arr[i][j] = 0;
swan.push_back({i, j});
}
}
}
bfs_swan(swan[0].first, swan[0].second);
for(int i = 0; i < r; i++){
for(int j = 0; j < c; j++){
cout << visited[i][j];
}
cout <<'\n';
}
// while (ice.size() && sw == 0)
// {
// melt_ice();
// cnt++;
// check_swan();
// }
cout << cnt;
}
이렇게 한번 해볼까요?
이렇게 하고 ex3을 입력하면
00000000000000000
00000000000000000
00000001100000000
00000011110000000
00000011110000000
00000011111000000
00000011111000000
00000001111000000
이런식으로 나옵니다.
이 때 만들어진 position을 기반으로 check_swan이 동작합니다.
이 함수는 똑같은 로직이죠.
void check_swan()
{
int x, y, nx, ny, psize, idx;
queue<pair<int, int>> q;
psize = position.size();
즉, 똑같은게 2번 반복됩니다.
또한, ice를 넣고
else if (str[j] == 'X')
{
arr[i][j] = -1;
ice.push({i, j});
}
이런식으로 네방향을 기반으로 바깥쪽의 얼음을 찾은 아이디어는 좋으나 비효율적입니다.
for (int i = 0; i < 4; i++)
{
ny = y + dy[i];
nx = x + dx[i];
if (ny >= r || ny < 0 || nx >= c || nx < 0) continue;
if (arr[ny][nx] == 0)
{
flag = 1;
q.push({y, x});
visited[y][x] = 0;
break ;
}
바깥부분부터 시작해 탐색을 이어가면 바깥 얼음이라는 것은 자명하니 이부분은 신경쓸필요가 없게 됩니다.
또 질문 있으시면 언제든지 질문 부탁드립니다.
좋은 수강평과 별점 5점은 제게 큰 힘이 됩니다. :)
감사합니다.
강사 큰돌 올림.
0
안녕하세요, 인프런 AI 인턴이에요.
주어진 코드에서 시간 초과가 발생하는 이유는 다양한 경우가 있을 수 있습니다. 하지만 코드를 보면서 몇 가지 개선해볼 점을 제시해드릴게요.
먼저, 주어진 문제에서 시간 초과가 발생한다면 가장 큰 원인은 탐색의 중복입니다. 따라서 중복된 탐색을 피하기 위해 이미 탐색한 위치를 기록하여 해당 위치를 다시 방문하지 않도록 하는 것이 좋습니다.
또한, 큐를 사용할 때 큐에 넣는 방식에 따라 성능이 달라질 수 있습니다. 현재 코드에서는 큐에 원소를 삽입하는 동안 큐의 크기만큼 반복문을 실행하고 있습니다. 이 경우 큐의 크기가 클수록 반복 횟수도 많아지므로 성능 저하의 원인이 될 수 있습니다. 이를 개선하기 위해서는 큐에 삽입할 때 바로 확인하는 방식으로 수정하는 것이 좋습니다.
그리고 큐에 넣는 위치를 단순히 모든 인덱스에 대해 확인하는 것이 아니라, 녹는 얼음의 위치 주변만 확인하도록 수정하는 것도 좋은 방법입니다. 이렇게 하면 불필요한 탐색을 줄일 수 있습니다.
마지막으로, BFS 탐색 시에는 방문한 위치를 체크하는 visited 배열을 사용하는 것이 좋습니다. 코드에서는 visited 배열을 초기화하지 않고 사용하고 있는 것 같아요. 따라서 탐색할 때마다 visited 배열을 초기화해주어야 합니다.
위의 점들을 참고하여 코드를 수정하고 실행해보세요. 그럼 좋은 결과를 얻을 수 있을 것입니다. 질문이 더 있으시면 언제든지 물어보세요. 좋은 결과 있길 바라요!
답변 감사합니다 ㅎㅎ
매번 초기 시작점에서부터 BFS가 불필요하게 일어납니다 <- 이 부분이 잘 이해가 안가서 그러는데요. 저는 while 문의 melt_ice, check_swan을 돌기전에 먼저 bfs_swan을 이용해서 백조가 다른 백조를 만날 수 있는지 확인을 하고 while문을 들어가는 로직으로 코드를 작성했는데 처음에 이 확인 작업이 잘못 되었다는 뜻인가요??