반응형

문제링크: https://www.acmicpc.net/problem/1365

 

1365번: 꼬인 전깃줄

첫 줄에 전봇대의 개수 N(1 ≤ N ≤ 100,000)이 주어지고, 이어서 N보다 작거나 같은 자연수가 N개 주어진다. i번째 줄에 입력되는 자연수는 길 왼쪽에 i번째 전봇대와 연결된 길 오른편의 전봇대가

www.acmicpc.net

최장 공통 수열 (LCS)를 도출하는 문제.

 

문제에 대한 설명은.... https://yhwan.tistory.com/18

 

[백준] 1365번: 꼬인 전깃줄 - C++

문제 출처:https://www.acmicpc.net/problem/1365  문제 공화국에 있는 유스타운 시에서는 길을 사이에 두고 전봇대가 아래와 같이 두 줄로 늘어서 있다. 그리고 길 왼편과 길 오른편의 전봇대는 하나의 전

yhwan.tistory.com

이분보다 잘할 자신이 없어서 이분꺼 참고

 

 

같은 논리로 작성하였는데, 정작 나는 이분탐색을 사용하지 않은 일반구현으로 제작했다.

아직까지 굳이 이분탐색으로 작성해야하는 이유를 못느끼고 있다.. (문제 검색에 올려놓음)

 

접근방식

 

1.  LCS 만큼의 전깃줄이 남아있을 수 있겠구나

2.  수의 범위가 커서 dp를 사용한 방식O(n^2)으로는 불가능 하겠구나 

 

 

문제풀이 

 

1.  일반적인 구현방식으로 해결

 

정답코드입니다.

아래 방식이 이분탐색을 사용하지 않아서 문제가 될 수 있을 것 같은데, 아직까지는 잘 모르겠습니다.

혹시 아시는 분은 댓글 부탁드립니다. 

 

 

--- ++ 추가 ---

아래방식은 해당 문제에서는 시간초과가 난다. 

최악의 경우에는 취약한 방법이기 때문이다. 따라서 이분탐색 방식을 권장한다.

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

 

12738번: 가장 긴 증가하는 부분 수열 3

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (-1,000,000,000 ≤ Ai ≤ 1,000,000,000)

www.acmicpc.net

 

단순 구현

#include <iostream>
#include <vector>
using namespace std;

int n = 0, temp;
vector <int> vec;
int lcs[100000];
int lcs_cnt = -1;


void low_bound(int num) {

	int val = vec[num];

	for (int i = 0; i <= lcs_cnt; i++) {
		if (val < lcs[i]) {
			lcs[i] = val;
			break;
		}

	}
}


int main() {

	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> temp;
		vec.push_back(temp);
	}

	for (int i = 0; i < vec.size(); i++) {

		if (lcs_cnt == -1)
			lcs[++lcs_cnt] = vec[i];
		else if (lcs[lcs_cnt] <= vec[i]) 
			lcs[++lcs_cnt] = vec[i];
		else if (lcs[lcs_cnt] > vec[i]) 
			low_bound(i);
		

	}
	
	
	
	cout << n - (lcs_cnt + 1) << endl;

	return 0;
}

이분탐색 적용

#include <iostream>
#include <vector>
using namespace std;

int n;
int arr[1000000];
vector <int> v;


int main() {
	ios_base::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> arr[i];

	for (int i = 0; i < n; i++) {
		if (v.size() == 0 || v[v.size() - 1] < arr[i]) v.push_back(arr[i]);
		else {
			int left = 0;
			int right = v.size();

			while (left <= right) {
				int mid = (left + right) / 2;
				if (v[mid] >= arr[i]) right = mid - 1;
				else left = mid + 1;
			}
			v[left] = arr[i];

		}


	}
	cout << n - v.size() << endl;
	return 0;
}
반응형

'알고리즘 > 기타' 카테고리의 다른 글

[백준] 1655-가운데를 말해요(C++)  (0) 2021.07.16
[백준] 11000-강의실 배정(C++)  (0) 2021.05.25
[백준] 1068-트리(C++)  (0) 2021.05.21
[백준] 1436-영화감독 숌(C++)  (0) 2020.04.02
[백준] 3020-개똥벌레(C++)  (0) 2020.03.21
반응형

문제링크: https://www.acmicpc.net/problem/3649

 

3649번: 로봇 프로젝트

각 테스트 케이스마다 한 줄에 하나씩, 구멍을 완벽하게 막을 수 있는 두 조각이 없다면 'danger'를 출력한다. 막을 수 있는 경우에는 'yes ℓ1 ℓ2'를 출력한다. (ℓ1 ≤ ℓ2) 정답이 여러 개인 경우에

www.acmicpc.net

 

일반적인 투포인터 문제

주의할 점은 "입력은 여러 개의 테스트 케이스로 이루어져 있다."  라는 말...

테스트케이스에서는 테스트가 반복되지않는 예시를 주는데, 입력을 여러번 받을 수 있도록 구현해야하는 문제.

 

while(cin>>a>>b)

 

위 처럼 작성함으로서 해당 문제는 해결

 

접근방식

 

1. 투 포인터를 가지고 값을 하나씩 조정해 보면서 결과를 도출한다. 

2. " |ℓ1 - ℓ2|가 가장 큰 것 " 이라는 조건을 유념하면서 

 

 

문제풀이 

 

1. 배열을 정렬

 

2. 일반적인 투포인터 처럼 값을 하나씩 옮기면서 구현

 

3. |ℓ1 - ℓ2|가 가장 클려면 인덱스의 간격이 가장 클 때(정렬 상태에서) 이니까 

결과값이 도출되면 바로 break! 

 

구현자체 난이도는 상당히 쉬운 편이었습니다.

 

정답코드입니다.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;


int main() {

	int x, n;
	
	while (cin >> x >> n) {
		x *= 10000000;
		vector<int> vec;
		int temp;

		for (int i = 0; i < n; i++) {
			cin >> temp;
			vec.push_back(temp);
		}
		sort(vec.begin(), vec.end());

		int low = 0, high = vec.size() - 1;
		bool flag = false;

		while (low < high) {

			int sum = vec[low] + vec[high];
			if (sum == x) {
				flag = true;
				break;
			}
			if (sum < x) { //low를 이동시켜줘야지..
				low++;
			}
			else { //sum > x
				high--;
			}


		}

		if (flag)
			cout << "yes " << vec[low] << ' ' << +vec[high] << endl;
		else
			cout << "danger" << endl;

	}



	return 0;
}

 

반응형
반응형

문제링크: https://www.acmicpc.net/problem/1477

 

1477번: 휴게소 세우기

첫째 줄에 현재 휴게소의 개수 N, 더 지으려고 하는 휴게소의 개수 M, 고속도로의 길이 L이 주어진다. N은 100보다 작거나 같으며, M도 100보다 작거나 같다. L은 100보다 크거나 같고, 1000보다 작거나

www.acmicpc.net

 

이분탐색임을 인지했는데, 어떻게 풀어나가야 할지 고민했던 문제

 

처음에는 간격이 제일 넓은 구획을 찾고, 그 두 간격을 반토막씩 자르면 어떨까 생각함

하지만 아래 처럼 휴게소가 배치되어있고, m = 2인 경우라면 

 

이렇게 추가가 되어짐...

 

당연히 오답.. 

 

 

 

거리가 비례하게끔, 아래 그림처럼 구성이 되어져야함 

 

 

고민하다가 "거리"로 이분 탐색해야 한다는 것을 깨닫게 됨.

 

 

 

접근방식

 

1. 위 설명처럼 거리를 통한 이분탐색을 생각하게 됨

2. 이분탐색에서의 조건은 휴게소 간격들 사이 해당 거리(mid) 만큼 지정했을 때, 배치 가능한 갯수 

 

 

문제풀이 

 

주석을 자세하게 적어 놓아기 때문에 생략

 

정답 코드입니다.

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int n, m, l;
vector <int> vec;

bool cmp(int& a, int& b) { // 없어도 되지만 간만에 짜보고 싶었어요ㅋㅋ
	if (a < b)
		return true;
	return false;
}

int main() {
	ios_base::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	cin >> n >> m >> l;
	int temp;
	vec.push_back(0), vec.push_back(l); //시작점과 끝점 추가 + 이미 휴게소가 있는 곳에 휴게소를 또 세울 수 없고, 고속도로의 끝에도 휴게소를 세울 수 없다. 라는 조건 때문에
	for (int i = 0; i < n; i++) {
		cin >> temp;
		vec.push_back(temp);
	}
	sort(vec.begin(), vec.end(), cmp);



	int low = 0, high = l;
	int mid, result = 0;

	while (low <= high) {
		mid = (low + high) / 2; 

		int val = 0; // 휴게소 사이에 배치 될 수있는 휴게소의 갯수
		for (int i = 1; i < vec.size(); i++) {
			int dist = vec[i] - vec[i - 1]; // 휴게소 a와 b 사이에 간격

			val += (dist / mid); // 휴게소 간격 / 현재 길이
			if (dist%mid == 0) //휴게소가 이미 있는 위치라면 
				val--; // 갯수를 하나 감소 시켜주어야지. 
		}
		if (val > m)  // 배치할 수 있는 휴게소가 m개 보다 많으면
			low = mid + 1; // 길이를 늘려주어 m개가 배치 되게끔 만들어주고 
		else {// 배치될 휴게소가 m개보다 작거나 같을 때 
			high = mid - 1;// 길이(mid)가 더 작아질 수 있을지 확인해야지  
			result = mid;  //결과값을 갱신해주기 
		}
	}

	cout << result << endl;

	return 0;
}

 

반응형
반응형

문제링크:https://www.acmicpc.net/problem/1072

 

1072번: 게임

김형택은 지금 몰래 Spider Solitaire(스파이더 카드놀이)를 하고 있다. 형택이는 이 게임을 이길 때도 있었지만, 질 때도 있었다. 누군가의 시선이 느껴진 형택이는 게임을 중단하고 코딩을 하기 시

www.acmicpc.net

 

 

일반 반복탐색은 1000000000번 탐색을 반복해야하기 때문에 무조건 시간초과(대략 10초)

킹반적인 이분탐색문제입니다.

 

이분탐색 개념이 모호하시다면, 아래 링크를 참고하세요! 

https://cjh5414.github.io/binary-search/

 

이진 탐색(Binary Search) 알고리즘 개념 이해 및 추가 예제

Jihun's Development Blog

cjh5414.github.io

 

접근방식

 

1. 일반적인 반복은 시초니까 이분탐색을 사용해보자

 

 

문제풀이 

 

1. result 를 -1로 저장한다. 만약 불가능하다면 result 값을 갱신하지 않아서 -1이 그대로 남게 된다.

 

2. 일반적인 이분탐색 방식으로 구현 코드를 보면 이해가 더 빠를듯

 

정답 코드입니다.

#include <iostream>
#include <cmath>
using namespace std;

double x, y;
double z;
int result = -1;


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

	cin >> x >> y;
	z = (y * 100) / x;
	z = floor(z);

	int low = 1;
	int high = 1000000000;

	while (low <= high) {
		int mid = (low + high) / 2; // 범위 ㄱㅊ
		double val = (double)((y + mid) * 100) / (x + mid);
		val = floor(val);
		if (val > z) {
			result = mid;
			high = mid - 1;
		}
		if (val <= z) {
			low = mid + 1;
		}
	}


	cout << result << endl;

	return 0;
}
반응형
반응형

문제링크: https://www.acmicpc.net/problem/16946

 

16946번: 벽 부수고 이동하기 4

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 한 칸에서 다른 칸으로 이동하려면, 두 칸이 인접해야 한다. 두 칸이

www.acmicpc.net

 

사소한 부분에서 틀렸던 문제...

4일 동안 반례를 못찾고 시름시름 앓고 있었는데, bamgoesn 님께서 반례를 찾아주셨다. ㅠㅠ

다시 한번 감사드립니다. ㅠㅠ

 

구현 + bfs 문제입니다. 

어떻게 보면 시뮬레이션이기도 하고, bfs 심화같기도 한 문제.

 

 

접근방식

 

1. 우선 빈칸들의 좌표별로 이동가능한 값들을 저장해야한다.

이때, 구획별로 번호를 매겨주어서 벽을 허물었을 때, 중복으로 구획을 세지 않도록 한다.

 

2. 벽을 하나씩 부서보면서 해당하는 좌표의 값을 도출한다. 

 

문제풀이 

 

1. bfs를 통해서 빈 좌표별로 이동가능한 최대한 값을 도출한다.

 

2. 다시 한번 bfs를 통해 이번엔 구획에 해당하는 모든 값들에 이동가능한 값과 구획번호를 저장

 

3. 벽 좌표를 vector에 저장하고 하나씩 부서보면서 결과를 도출

이때, 구획번호가 중복이 되지 않겠끔 vector에 구획번호를 저장하면서 4방향을 모두 확인 

 

 

정답코드입니다. 

#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
using namespace std;

int n, m;
int arr[1001][1001] = { 0, };
vector <pair<int, int>> block;
int result[1001][1001] = { 0, };

int visited[1001][1001][2] = { 0, }; // 첨에는 이동 가능한 개수를 저장할거고, 두번째에는 고유 영역 값을 저장할 예정
int vis_cnt = 1; // 구획의 첫 번호는 1부터 

bool temp_v[1001][1001] = { 0, }; //난 bfs로 구현할거야, 얘는 탐색을 위해 사용할 배열

int y_ar[4] = { -1,0,1,0 };
int x_ar[4] = { 0,1,0,-1 };


void bfs(int ty, int tx) {

	// 1. temp_v를 사용해서 이동 가능한 개수 파악하기
	int maxed = 1;
	temp_v[ty][tx] = 1;
	queue <pair<int, int>> que;
	que.push(make_pair(ty, tx));

	while (!que.empty()) {
		int cy = que.front().first;
		int cx = que.front().second;
		que.pop();

		for (int i = 0; i < 4; i++) {
			int ny = cy + y_ar[i];
			int nx = cx + x_ar[i];
			if (ny < 0 || ny >= n || nx < 0 || nx >= m || arr[ny][nx] != 0)
				continue;
			if (temp_v[ny][nx] != 0)
				continue;
			temp_v[ny][nx] = 1;
			que.push(make_pair(ny, nx));
			maxed++;
		}
	}
	//cout << maxed << endl;

	// 2. visited에 이동가능한 개수와 자신의 구획번호를 입력하기 
	visited[ty][tx][0] = maxed;
	visited[ty][tx][1] = vis_cnt;
	que.push(make_pair(ty, tx));

	while (!que.empty()) {
		int cy = que.front().first;
		int cx = que.front().second;
		que.pop();

		for (int i = 0; i < 4; i++) {
			int ny = cy + y_ar[i];
			int nx = cx + x_ar[i];
			if (ny < 0 || ny >= n || nx < 0 || nx >= m || arr[ny][nx] != 0)
				continue;
			if (visited[ny][nx][0] != 0)
				continue;
			visited[ny][nx][0] = maxed;
			visited[ny][nx][1] = vis_cnt;
			que.push(make_pair(ny, nx));
		}
	}



	vis_cnt++; //인덱스를 하나 올려준다.


}

int main() {
	ios_base::sync_with_stdio(0);

	cin >> n >> m;

	for (int i = 0; i < n; i++) {
		string temp;
		cin >> temp;
		for (int j = 0; j < m; j++) {
			arr[i][j] = temp[j] - '0';
			if (arr[i][j] == 1)
				block.push_back(make_pair(i, j));
		}
	}

	//cout << block.size() << endl;

	//1. 영역별로 마킹하기!

	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			if (temp_v[i][j] == 0 && arr[i][j] == 0) { // 벽이 아니고, 방문한 적이 없다면 탐색해야해!
				bfs(i, j);
			}

	/*
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cout << visited[i][j][1] << ' ';
		}
	cout << endl;
	}
	*/

	//2. 벽을 하나씩 부수면서 이동가능한 결과값을 도출하는 과정 

	vector <int> index; // index 값들을 임시 저장할 친구 
	for (int i = 0; i < block.size(); i++) {
		index.clear();
		int val = 1; //자신을 포함해야 하니 1 부터 시작한다. 
		
		int y = block[i].first;
		int x = block[i].second;

		for (int j = 0; j < 4; j++) {
			bool flag2 = true;
			int ny = y + y_ar[j];
			int nx = x + x_ar[j];

			if (ny < 0 || ny >= n || nx < 0 || nx >= m || arr[ny][nx] == 1)
				continue;
			for (int i = 0; i < index.size(); i++)
				if (visited[ny][nx][1] == index[i]) {
					flag2 = false;
					break;
				}
			if (flag2 == true) {
				val += visited[ny][nx][0];
				index.push_back(visited[ny][nx][1]);
			}
			
		}

		result[y][x] = val % 10;
	}


	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++)
			printf("%d", result[i][j]);
		printf("\n");
	}

}

 

 

 

반응형
반응형

문제링크: https://www.acmicpc.net/problem/14466

 

14466번: 소가 길을 건너간 이유 6

첫 줄에 N, K, R이 주어진다. 다음 R줄에는 한 줄에 하나씩 길이 주어진다. 길은 상하좌우로 인접한 두 목초지를 잇고, r c r′ c′의 형태 (행, 열, 행, 열)로 주어진다. 각 수는 1 이상 N 이하이다.

www.acmicpc.net

 

문제를 이해하는데 오래 걸렸습니다.

즉 N x N 구역의 좌표들에 소가 분포해있습니다.

 

문제에서 주어지는 길을 피해서 이동하여 소들은 만날 수가 있겠죠.

하지만 특정한 소들은 꼭 길을 포함해서 이동할때에만 만날 수가 있습니다.

그 소의 개수를 출력하라는 문제입니다.

 

문제에서 주어진 예시에서는 

A(3,3), B(2,2), C(2,3)  이렇게 3마리 소가 있습니다. 

B(2,2)와 C(2,3)는 2,2 -> 1,2 -> 1,3 -> 2,3 경로로 움직여서 길을 포함하지 않더라도 만날 수 있습니다.

하지만 A,B와 A,C는 길을 포함하지 않고 만날 수 가 없습니다. 

그래서 총 2쌍이라는 겁니다.

 

 

접근방식

 

1. 일반적인 bfs로 구현해보자

 

문제풀이 

 

1. 길을 마킹할 배열 arr[101][101][4] 를 생성 북,동,남,서 순으로 이동이 불가한 위치를 표시할 용도

2. bfs를 통해 소 기준으로 이동이 불가한 소들을 도출

3. bfs를 반복해줄때, 이전 소들은 확인할 필요없이 자신보다 인덱스가 높은 소들만 확인해주면서 넘어가야 중복이 안생김

 

 

코드를 직접 확인하는게 더 빠를 것 같음

#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;

int n, k, R;
int arr[101][101][4] = { 0, }; // 4방향에 대해서 길이 있을 수 있으니.. 북 동 남 서 순으로 저장할거
bool visited[101][101];
int y_ar[4] = { -1,0,1,0 };
int x_ar[4] = { 0,1,0,-1 };

vector <pair<int, int>> cow;
int result = 0;
void bfs(int sy, int sx) {

	queue <pair<int, int >> que;
	que.push(make_pair(sy, sx));
	visited[sy][sx] = 1;

	while (!que.empty()) {
		int cy = que.front().first;
		int cx = que.front().second;
		que.pop();

		for (int i = 0; i < 4; i++) {
			if (arr[cy][cx][i] == 1) continue; //도로가 있는건 탐색 안해줄거야
			int ny = cy + y_ar[i];
			int nx = cx + x_ar[i];

			if (ny <1 || ny > n || nx < 1 || nx > n || visited[ny][nx] == 1)
				continue;
			que.push(make_pair(ny, nx));
			visited[ny][nx] = 1;
		}



	}


}
int main() {
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	cin >> n >> k >> R;

	int r, c, rr, cc;
	for (int i = 0; i < R; i++) {
		cin >> r >> c >> rr >> cc;
		for (int j = 0; j < 4; j++) {
			int nr = r + y_ar[j];
			int nc = c + x_ar[j];
			if (nr == rr && nc == cc) {
				arr[r][c][j] = 1; // 다리 생성
				arr[rr][cc][(j + 2)%4] = 1;
			}
		}
	}

	for (int i = 0; i < k; i++) {
		cin >> r >> c;
		cow.push_back(make_pair(r, c)); 
	}

	for (int i = 0; i < k; i++) {
		memset(visited, 0, sizeof(visited));
		bfs(cow[i].first, cow[i].second);

		for (int j = i + 1; j < k; j++) {
			if (visited[cow[j].first][cow[j].second] == 0)
				result++;
		}
	}


	cout << result << endl;
	return 0;
}

 

 

반응형

'알고리즘 > BFS' 카테고리의 다른 글

[백준] 3108-로고(C++)  (0) 2021.08.16
[백준] 16946-벽 부수고 이동하기 4(C++)  (0) 2021.08.11
[백준] 16954-움직이는 미로 탈출(C++)  (2) 2021.08.01
[백준] 2151-거울 설치(C++)  (0) 2021.08.01
[백준] 1039-교환(C++)  (0) 2021.07.26
반응형

문제링크: https://www.acmicpc.net/problem/1956

 

1956번: 운동

첫째 줄에 V와 E가 빈칸을 사이에 두고 주어진다. (2 ≤ V ≤ 400, 0 ≤ E ≤ V(V-1)) 다음 E개의 줄에는 각각 세 개의 정수 a, b, c가 주어진다. a번 마을에서 b번 마을로 가는 거리가 c인 도로가 있다는 의

www.acmicpc.net

 

대표적인 플로이드 와샬 문제입니다.

플로이드 와샬에 대한 이해가 필요합니다. 

 

O(V^3) 만큼 반복하면서 모든 노드의 최단거리를 도출하고 결과값을 도출하는 문제입니다.

 

 

아래는 정답 코드입니다.

#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
/*

주의점
1. 중복경로에 대한 예외처리
2. long long
*/

int v, e;
long long arr[401][401];

int main() {
	ios_base::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	cin >> v >> e;
	for (int i = 1; i <= v; i++)
		for (int j = 1; j <= v; j++) {
			if (i == j) arr[i][j] = 0;
			else arr[i][j] = 2000000000; 	
		}

	int a, b, c;
	for (int i = 0; i < e; i++) {
		cin >> a >> b >> c;
		if (arr[a][b] > c) //중복경로
			arr[a][b] = c;
	}

	//플로이드 와샬
	for (int k = 1; k <= v; k++)
		for (int i = 1; i <= v; i++)
			for (int j = 1; j <= v; j++)
				arr[i][j] = min(arr[i][j], arr[k][j] + arr[i][k]);

	long long result = 2000000000;

	for (int i = 1; i <= v; i++)
		for (int j = 1; j <= v; j++) {
			if (i == j) continue;
			result = min(result, arr[i][j] + arr[j][i]);
		}
	if (result == 2000000000)
		cout << -1 << endl;
	else
		cout << result << endl;
	return 0;
}
반응형
반응형

문제링크: https://www.acmicpc.net/problem/16954

 

16954번: 움직이는 미로 탈출

욱제는 학교 숙제로 크기가 8×8인 체스판에서 탈출하는 게임을 만들었다. 체스판의 모든 칸은 빈 칸 또는 벽 중 하나이다. 욱제의 캐릭터는 가장 왼쪽 아랫 칸에 있고, 이 캐릭터는 가장 오른쪽

www.acmicpc.net

 

bfs, 시뮬레이션 문제

 

 

접근방식

 

1. 욱제라는 사람의 이동은 bfs로 구현이 가능

2. 욱제이동과 벽이동을 번갈아가며 진행하면서 결과값을 도출하자

 

문제풀이 

 

1. bfs를 통해서 이동이 가능한 경로를 저장하며 진행

이때, 방문노드는 매턴마다 초기화하는데 그 이유는 다음턴에 다시 해당좌표로 이동할수도 있기 때문

........

........

........

........

........

.#######

#.......

........

ex) 위와 같은 예제에서 첨좌표로 되돌아 오는 것

 

2. 벽이동은 벽좌표들을 vector에 넣어 관리하며 진행 

 

 

#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <queue>
using namespace std;

typedef struct a {
	int y;
	int x;
}dir;

dir d[9] = { {0,0}, {-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1} };
string arr[8]; // 0base; 시작점은 7,0 도착점은 0,7 이다.
vector <dir> vec; // 벽을 저장할 벡터
queue <dir> que;

bool result = 0;
bool visited[8][8];

int main() {
	ios_base::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	for (int i = 0; i < 8; i++) {
		cin >> arr[i];
		for (int j = 0; j < 8; j++) {
			if (arr[i][j] == '#')
				vec.push_back({ i,j });
		}
	}
	que.push({ 7,0 });

	while (!que.empty()) { //큐가 비었으면 종료되는 구조 

		//1. 욱제의 이동
		int cnt = que.size();
		memset(visited, 0, sizeof(visited));

		while (cnt--) { // 갯수만큼

			int y = que.front().y;
			int x = que.front().x;
			que.pop();
			

			if (y == 0 && x == 7) {
				result = true;
				break;
			} 
			if (arr[y][x] == '#') //벽이 캐릭터가 있는 칸으로 이동하면 더 이상 캐릭터는 이동할 수 없다.
				continue;

			for (int i = 0; i < 9; i++) {
				int ny = y + d[i].y;
				int nx = x + d[i].x;
				if (ny < 0 || ny > 7 || nx < 0 || nx > 7 || arr[ny][nx] == '#') //방문여부는 체크하지 않는다 왔다 갔다 할수도 있자나 
					continue;
				if (visited[ny][nx] == 1)
					continue;
				visited[ny][nx] = 1;
				que.push({ ny,nx });
			}
		}

		//2. 벽이동
		
		for (int i = 0; i < 8; i++)
			arr[i] = "........";
		for (int i = 0; i < vec.size(); i++) {
			int y = vec[i].y;
			int x = vec[i].x;

			if (y == 7) {
				vec.erase(vec.begin() + i);
				i--;
			
				continue;
			}


			arr[y + 1][x] = '#';
			vec[i].y++;

		}

		if (result == true) //도달했으면 조기종료 
			break;
		
		/*
		cout << endl;
		for (int i = 0; i < 8; i++) {
			for (int j = 0; j < 8; j++)
				cout << visited[i][j];
			cout << endl;
		}
		cout << endl;
		for (int i = 0; i < 8; i++) {
			for (int j = 0; j < 8; j++)
				cout << arr[i][j];
			cout << endl;
		}
		cout << "quesize " << que.size() << endl;
		*/
	}


	cout << result << endl;
	return 0;
}
반응형

+ Recent posts