반응형

문제링크:www.acmicpc.net/problem/1516

 

1516번: 게임 개발

첫째 줄에 건물의 종류 수 N(1 ≤ N ≤ 500)이 주어진다. 다음 N개의 줄에는 각 건물을 짓는데 걸리는 시간과 그 건물을 짓기 위해 먼저 지어져야 하는 건물들의 번호가 주어진다. 건물의 번호는 1부

www.acmicpc.net

 

문제를 보자마자 아이디어는 금방 떠올랐습니다.

 

문제조건에서 

  • 편의상 자원은 무한히 많이 가지고 있고,
  • 건물을 짓는 명령을 내리기까지는 시간이 걸리지 않는다

하였으니 단순히 이전 건물을 짓는데 시간과 자신의 건축시간을 더한 값입니다.

 

dp[num]을 자신의 건물 완성 최소시간이라 할때

dp[num] = 자신의 건축시간 + max(선이수 건물 완성 최소시간) 입니다.

 

 

이때 구현방법을 고민해봐야 합니다.

일반적인 dp구현방식인 (down-up) 방식을 사용할 수 없습니다. 선이수 건물이 이미 완성 되었는지 모르기 때문입니다.

즉, 재귀호출방식(up-down)방식을 사용해야합니다. 이때 이미 구한 값은 비트마스킹 과정을 통해 값을 저장하고, 중복해서 계산하지 않는 것이 포인트 입니다.

 

 

 

아래는 정답코드입니다.

구조체 벡터때문에 복잡해보이지만 굉장히 간단한 논리입니다. 천천히 확인해 보세요!

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

typedef struct MyStruct
{
	int time;
	vector <int> prefer;

}val;
val arr[501];
int n;
int dp[501];

int solved(int num) {

	if (dp[num] != 0) return dp[num];


	int maxed = 0;
	for (int i = 0; i < arr[num].prefer.size(); i++) {
		maxed = max(maxed, solved(arr[num].prefer[i]));
	}
	dp[num] = maxed + arr[num].time;
	return dp[num];
}

int main() {

	ios_base::sync_with_stdio(false);
	cin.tie(0);

	cin >> n;

	for (int i = 1; i <= n; i++) {
		cin >> arr[i].time;
		int temp;
		while (1) {
			cin >> temp;
			if (temp == -1) {
				break;
			}
			arr[i].prefer.push_back(temp);
		}
	}
	/*
	for (int i = 1; i <= n; i++)
		cout << arr[i].prefer.size() << endl;
	*/

	for (int i = 1; i <= n; i++)
		cout << solved(i) << endl;

	return 0;
}

 

재귀를 쓰지않고 bfs를 활용해서도 답을 얻을 수 있습니다.

#include<iostream>
#include<queue>
#include<vector>
using namespace std;
int degree[501] = { 0, };
int N, n;
vector<int> vec[501];
int time[501], result[501];

void bfs() {
	queue<int> q;
	for (int i = 1; i <= N; i++) {
		if (degree[i] == 0) {
			q.push(i);
			result[i] = time[i];
		}
	}

	while (!q.empty()) {
		int front = q.front();
		q.pop();
		for (int i = 0; i < vec[front].size(); i++) {
			int e = vec[front][i];
			result[e] = max(result[e], result[front] + time[e]);
			if (--degree[e] == 0)
				q.push(e);
		}
		
	}
}


int main(void) {
	cin.tie(NULL);
	ios::sync_with_stdio(false);

	cin >> N;
	for (int i = 1; i <= N; i++) {
		cin >> n;
		time[i] = n;
		while (1) {
			cin >> n;
			if (n == -1)	break;
			vec[n].push_back(i);
			degree[i]++;
		}
	}
	bfs();
	for (int i = 1; i <= N; i++)
		cout << result[i] << "\n";
	return 0;
}
반응형

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

[백준] 12865-평범한 배낭(C++), 배낭 문제 알고리즘  (0) 2020.12.17
[백준] 11062-카드 게임(C++)  (0) 2020.12.16
[백준] 2482-색상환(C++)  (0) 2020.12.15
[백준] 2056-작업(C++)  (0) 2020.12.15
[백준] 1256-사전(C++)  (0) 2020.09.13
반응형

문제링크:www.acmicpc.net/problem/14719

 

14719번: 빗물

첫 번째 줄에는 2차원 세계의 세로 길이 H과 2차원 세계의 가로 길이 W가 주어진다. (1 ≤ H, W ≤ 500) 두 번째 줄에는 블록이 쌓인 높이를 의미하는 0이상 H이하의 정수가 2차원 세계의 맨 왼쪽 위치

www.acmicpc.net

 

평범한 구현문제입니다.

 

문제에서 준 조건은 2가지 입니다.

 

  • 블록내부에 빈공간은 생기지 않는다.
  • 바닥은 막혀있다 가정한다.

 

h와 w의 범위가 1 ~ 500 까지 임으로 단순 구현을 통해서 문제를 해결했습니다.  O(n^3)

 

 

500 x 500 각각의 좌표에서 빗물이 보관되는지 확인하여 구현했습니다.

쉬운문제이기 때문에 코드를 보시면 금방 이해하실겁니다.

 

 

정답코드입니다.

#include <iostream>
using namespace std;


int h = 0, w = 0;
int arr[501] = { 0, };
int result = 0;
int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0);

	cin >> h >> w;
	for (int i = 1; i <= w; i++)
		cin >> arr[i];
	for (int i = 1; i <= h; i++) {
		for (int j = 2; j <= w - 1; j++) {
			if (arr[j] >= i) continue;

			bool leftt = false;
			bool rightt = false;
			//left identify
			for (int k = j - 1; k >= 1; k--) {
				if (arr[k] >= i)
				{
					leftt = true;
					break;
				}
			}
			//right identify
			for (int k = j + 1; k <= w; k++) {
				if (arr[k] >= i)
				{
					rightt = true;
					break;
				}
			}

			if (leftt == true && rightt == true)
				result++;
		}
	}

	cout << result << endl;

	return 0;
}
반응형

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

[백준] 2116-주사위 쌓기(C++)  (0) 2020.12.18
[백준] 2636-치즈(C++)  (0) 2020.12.18
[백준] 5624-좋은 수  (0) 2020.08.08
[백준] 6593-상범 빌딩(C++)  (0) 2020.07.05
[백준] 5549-행성 탐사(C++)  (0) 2020.06.14
반응형

문제링크:www.acmicpc.net/problem/2482

 

2482번: 색상환

첫째 줄에 N색상환에서 어떤 인접한 두 색도 동시에 선택하지 않고 K개의 색을 고를 수 있는 경우의 수를 1,000,000,003 (10억 3) 으로 나눈 나머지를 출력한다.

www.acmicpc.net

 

dp문제입니다. 점화식을 생각하는데 오래 걸렸습니다.

 

인접하게 칠할 수 없다는 조건이 있습니다.

 

dp[N][K] = N 개 짜리 색에서 K 개를 인접하지 않게 칠하는 경우의 수

 

점화식 : dp[n][k] = dp[n-2][k-1] + dp[n-1][k] 

 

 

표를 작성하면서 해당 점화식 규칙을 알게 되었습니다. 두개이상의 색을 구할때는 색칠한 경우와 하지 않은 경우로 구분하여 생각하면 됩니다. 

 

아래는 정답코드입니다.

#include <iostream>
using namespace std;

int dp[1001][1001] = { 0 };
int n = 0, k = 0;
int result = 0;

int main() {

	ios_base::sync_with_stdio(false);
	cin.tie(0);

	cin >> n >> k;

	for (int i = 1; i <= n; i++) {
		dp[i][1] = i;
		for (int j = 2; j <= i / 2; j++) {
			dp[i][j] = (dp[i - 1][j] + dp[i - 2][j - 1]) % 1000000003;
		}
	}
	/*
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= 3; j++)
			cout << dp[i][j] << ' ';
		cout << endl;
	}*/
	result = dp[n][k];
	cout << result << endl;

	return 0;
}

 

반응형

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

[백준] 11062-카드 게임(C++)  (0) 2020.12.16
[백준] 1516-게임개발(C++)  (0) 2020.12.16
[백준] 2056-작업(C++)  (0) 2020.12.15
[백준] 1256-사전(C++)  (0) 2020.09.13
[백준] 13398-연속합2(C++)  (0) 2020.09.06
반응형

문제링크:www.acmicpc.net/problem/2056

 

2056번: 작업

수행해야 할 작업 N개 (3 ≤ N ≤ 10000)가 있다. 각각의 작업마다 걸리는 시간(1 ≤ 시간 ≤ 100)이 정수로 주어진다. 몇몇 작업들 사이에는 선행 관계라는 게 있어서, 어떤 작업을 수행하기 위해

www.acmicpc.net

 

 

dp문제라기보다는 그리디 문제에 가까웠습니다. 

 

문제에서 주는 조건들입니다.

 

  • 항상 선행작업부터 처리한다.
  • 선행작업의 번호는 자신의 번호보다 작다.
  • 선행작업이 아니라면 동시작업이 가능하다.

3가지 규칙에 의해서 1번작업부터 오름차순으로 작업시간을 정의내리면 결과값을 도출할 수 있습니다.

 

 

굳이 점화식으로 나타내자면,   dp[n] = current_time + max( 1~dp[n-1]) 일것입니다. 

그리고 이러한 값들중 가장 큰 값이 결과값이 되는 것입니다. 

 

문제의 원리를 이해하셨다면 구현자체는 전혀 어려움이 없으셨을겁니다.

 

 

아래는 정답코드입니다. 

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

int dp[10001] = { 0, };
int n;
int time = 0, cnt = 0, value = 0;
int result = 0;

int main(void) {

	iostream::sync_with_stdio(false);
	cin.tie(0);

	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> time >> cnt;
		if (cnt == 0) {
			dp[i] = time;
			continue;
		}
		int maxed = 0;
		for (int j = 0; j < cnt; j++) {
			cin >> value;
			maxed = max(maxed, dp[value]);
		}
		dp[i] = time + maxed;
	}
	/*
	for (int i = 1; i <= n; i++)
		cout << dp[i] << endl;
	*/


	for (int i = 1; i <= n; i++)
		result = max(result, dp[i]);

	cout << result << endl;


	return 0;
}

 

반응형

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

[백준] 1516-게임개발(C++)  (0) 2020.12.16
[백준] 2482-색상환(C++)  (0) 2020.12.15
[백준] 1256-사전(C++)  (0) 2020.09.13
[백준] 13398-연속합2(C++)  (0) 2020.09.06
[백준] 2688-줄어들지 않아(C++)  (0) 2020.06.15
반응형

문제링크:www.acmicpc.net/problem/1256

 

1256번: 사전

첫째 줄에 N, M, K가 순서대로 주어진다. N과 M은 100보다 작거나 같은 자연수이고, K는 1,000,000,000보다 작거나 같은 자연수이다.

www.acmicpc.net

 

dp 문제였습니다.

 

우선 규칙성을 이해하기 위해 n과 m 개수에 따른 경우의 수를 생각해봤습니다.

z/a 0 1 2 3
0 0 1 1 1
1 1 2 3 4
2 1 3 6 10
3 1 4 10 20

즉 경우의 수는 dp[i][j] = dp[i][j-1] + dp[i-1][j] 입니다. 

 

 

이때 어떠한 규칙으로 az의 조합이 결정되는지 생각해보겠습니다.

 

ex) 2 2 2 일 경우

dp[2][2] = 6이고 dp[2][1], dp[1][2] = 3 이다. 2번째 문자열일 경우 첫문자는 a가 되고 dp[2][1]에 속하게 된다. 

dp[2][1]에서도 2번째 문자열이다. dp[1][1] = 2, dp[2][0] = 1 이므로 두번째 문자는 z가 되고 dp[1][1]에 속하게 된다.

이런 형태로 반복하면 azaz가 된다.

 

for(int i=0;i<n+m;i++) {
		int a_start = dp[a_cnt - 1][z_cnt];
		int z_start = dp[a_cnt][z_cnt - 1];

		//cout << a_start << endl;
		if (a_cnt == 0) {
			cout << 'z';
			z_cnt--;
			continue;
		}
		else if (z_cnt == 0) {
			cout << 'a';
			a_cnt--;
			continue;
		}

		if (k <= a_start) {
			cout << 'a';
			a_cnt--;
		}
		else {
			k = k - a_start;
			cout << 'z';
			z_cnt--;
		}


	}

위와 같은 형태로 진행해주면 된다.

 

한가지 조심해야할 점은 K는 1,000,000,000보다 작거나 같은 자연수라는 점이다. 나도 이 부분 때문에 꽤 애먹었다. 

k가 10억이기 때문에 n과 m의 경우의수 int형의 범위는 물론이고 long long의 범위를 쉽게 넘어가는 경우가 발생한다. 

이 때 오버플로우에 의해서 음수가 저장되며  경우의 수 값이 달라질 수 있기 때문에 1,000,000,000이 넘어가면 그냥 1,000,000,000을저장하여 문제를 해결하였다.  어차피 1,000,000,000번째 까지의 문자열을 확인해줄거기 때문에 값이 더 클 때 1,000,000,000이라고 저장하는게 유효한 것이다. 어차피 그러면 앞에 a인 것을 동일하기 때문이다.

이거를 이해하는데 오래 걸렸다. ㅠㅠ

 

정답코드입니다.

 

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



int n = 0, m = 0;
int k = 0;

long long dp[101][101];




int main() {

	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	cin >> n >> m >> k;

	for (int i = 1; i <= 100; i++)
		dp[i][0] = 1, dp[0][i] = 1;

	for (int i = 1; i <= 100; i++)
		for (int j = 1; j <= 100; j++) {
			dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
			if (dp[i][j] > 1000000000) dp[i][j] = 1000000000;
		}
	
	int a_cnt = n;
	int z_cnt = m;
	if (dp[n][m] < k) {
		cout << -1 << endl;
		return 0;
	}
		
	for(int i=0;i<n+m;i++) {
		int a_start = dp[a_cnt - 1][z_cnt];
		int z_start = dp[a_cnt][z_cnt - 1];

		//cout << a_start << endl;
		if (a_cnt == 0) {
			cout << 'z';
			z_cnt--;
			continue;
		}
		else if (z_cnt == 0) {
			cout << 'a';
			a_cnt--;
			continue;
		}

		if (k <= a_start) {
			cout << 'a';
			a_cnt--;
		}
		else {
			k = k - a_start;
			cout << 'z';
			z_cnt--;
		}


	}

	cout << "\n";
	return 0;
}

 

 

반응형

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

[백준] 2482-색상환(C++)  (0) 2020.12.15
[백준] 2056-작업(C++)  (0) 2020.12.15
[백준] 13398-연속합2(C++)  (0) 2020.09.06
[백준] 2688-줄어들지 않아(C++)  (0) 2020.06.15
[백준] 11049-행렬 곱셈 순서(C++)  (0) 2020.06.13
반응형

문제링크:www.acmicpc.net/problem/13398

 

13398번: 연속합 2

첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.

www.acmicpc.net

 

쉬운 dp 문제였습니다.

 

조건은 두가지입니다. 

1. 수열에서 수를 하나 제거할 수 있다.

2. 제거하지 않아도 된다.

 

우선 제거하지 않을때는 

if (dp[i - 1][0] > 0)
dp[i][0] = arr[i] + dp[i - 1][0];
else
dp[i][0] = arr[i];

로 쉽게 구할 수 있습니다.

 

그리고 하나의 수를 제거할 때는 

1) 현재 자신을 제거한 값이 큰지,

2) 이전에 제거한 값 + 현재값이 큰지

비교합니다.

 

정답코드입니다.

너무 쉬워서 점화식은 따로 기재하지 않았습니다.

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

/* 
제거 한경우 제거 안한 경우 

10 -4  3 1 5 6  -35 12 21 -1

0: 10 6 9 10 15 21 -14 -2 19 18   
1: 0 10 13   
현재 자신에서 뺀값이라 이미 빠진값이랑 비교해서 더큰값으로 넣는다. 
*/

int dp[100001][2] = { 0 };
int arr[100001] = { 0 };
int n = 0, result = -1000000000;
int main() {
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> arr[i];

	dp[1][0] = arr[1];

	for (int i = 2; i <= n; i++) {
		if (dp[i - 1][0] > 0)
			dp[i][0] = arr[i] + dp[i - 1][0];
		else
			dp[i][0] = arr[i];
	}
	
	dp[1][1] = 0;

	for (int i = 2; i <= n; i++) {
		//1. 자신을 제외했을때 값과 이미 제한값을 비교
		int a = dp[i - 1][0]; //자신을 제외했을때
		int b = dp[i - 1][1] + arr[i];
		dp[i][1] = max(a, b);
	}

	for (int i = 2; i <= n; i++) {
		if (result < dp[i][0]) result = dp[i][0];
		if (result < dp[i][1])	result = dp[i][1];
	}
	if (result < dp[1][0]) result = dp[1][0];




	if (n == 1) cout << arr[1] << endl;
	else cout << result << endl;
	return 0;
}

  

반응형

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

[백준] 2056-작업(C++)  (0) 2020.12.15
[백준] 1256-사전(C++)  (0) 2020.09.13
[백준] 2688-줄어들지 않아(C++)  (0) 2020.06.15
[백준] 11049-행렬 곱셈 순서(C++)  (0) 2020.06.13
[백준] 11066-파일 합치기(C++)  (0) 2020.06.11
반응형

문제링크:www.acmicpc.net/problem/19236

 

19236번: 청소년 상어

첫째 줄부터 4개의 줄에 각 칸의 들어있는 물고기의 정보가 1번 행부터 순서대로 주어진다. 물고기의 정보는 두 정수 ai, bi로 이루어져 있고, ai는 물고기의 번호, bi는 방향을 의미한다. 방향 bi는

www.acmicpc.net

 

 

 

삼성 코딩테스트에서 나온 청소년 상어입니다. 

기존 아기상어는 쉽게 접근했는데 청소년상어는 애먹었습니다.

 

우선 크게 

1. 물고기의 이동

2. 상어의 이동 

으로 구분할 수 있습니다.

 

물고기는 이동이 불가할 경우 반시계방향으로 방향을 방향을 바꾸게 됩니다. 

그렇기 때문에 첫번째 이동과 두번째 이상부터의 이동을 구분해주어야 합니다. (방향을 다르게 설정해주기 때문에)

 

 

아래가 물고기 이동의 코드입니다.

	// fish
	for (int i = 1; i <= 16; i++) {
		if (fishes[i].alive== false)
			continue;
		int y = fishes[i].y;
		int x = fishes[i].x;
		int dir = fishes[i].dir;

		int ny = y + y_ar[dir];
		int nx = x + x_ar[dir];
		bool jud = false;

		if (ny >= 0 && ny < 4 && nx >= 0 && nx < 4) {
			if (arr[ny][nx] == 0) { //없으면

				jud = true;
				fishes[i].y = ny;
				fishes[i].x = nx;
				arr[ny][nx] = i;
				arr[y][x] = 0;
				
			}
			else if (arr[ny][nx] != -1) {// 물고기가 있으면
				jud = true;
			
				fish temp = fishes[i];
				fishes[i].y = fishes[arr[ny][nx]].y;	
				fishes[i].x = fishes[arr[ny][nx]].x;
				fishes[arr[ny][nx]].y = temp.y;
				fishes[arr[ny][nx]].x = temp.x;

				int temp2;
				temp2 = arr[y][x];
				arr[y][x] = arr[ny][nx];
				arr[ny][nx] = temp2;

			}


		}
		if (jud == true) continue;
		else {
			int ndir = dir + 1;
			if (ndir == 9) ndir = 1;
			int ny = y + y_ar[ndir];
			int nx = x + x_ar[ndir];


			while (ndir != dir) {
				if (ny >= 0 && ny < 4 && nx >= 0 && nx < 4) {
					if (arr[ny][nx] == 0) { //없으면

						
						fishes[i].y = ny;
						fishes[i].x = nx;
						fishes[i].dir = ndir;
						arr[ny][nx] = i;
						arr[y][x] = 0;

						break;
					}
					else if (arr[ny][nx] != -1) {// 물고기가 있으면
						
						fish temp = fishes[i];
						fishes[i].y = fishes[arr[ny][nx]].y;
						fishes[i].x = fishes[arr[ny][nx]].x;
						fishes[arr[ny][nx]].y = temp.y;
						fishes[arr[ny][nx]].x = temp.x;
						

						int temp2;
						temp2 = arr[y][x];
						arr[y][x] = arr[ny][nx];
						arr[ny][nx] = temp2;

						fishes[i].dir = ndir;
						break;

					}

				}
				ndir++;
				if (ndir == 9) ndir = 1;
				ny = y + y_ar[ndir];
				nx = x + x_ar[ndir];

			}
		}



	}

 

 

이후 상어의 이동은 dfs로 구현하고 갈 수 있는 모든 경우를 고려해줍니다.

 

	// 상어의 이동
	//1. 해당 방향으로 이동 (가능한 경우 모두)	
	
	int nx = shark.x;
	int ny = shark.y;

	while (1) {

		ny += y_ar[shark.dir];
		nx += x_ar[shark.dir];

		if (ny >= 0 && ny < 4 && nx >= 0 && nx < 4) {


			//1. 상어의 위치 바꾸기 2. 그 위치에 물고기
			if (arr[ny][nx] == 0) continue;


			int fishnum = arr[ny][nx];
			int ndir = fishes[fishnum].dir;

			arr[shark.y][shark.x] = 0;
			arr[ny][nx] = -1;
			shark = fishes[fishnum];
			fishes[fishnum].alive = false;


			dfs(fishes, shark, arr, cnt + fishnum);

			fishes[fishnum].alive = true;
			arr[ny][nx] = fishnum;
			shark = b;
			arr[shark.y][shark.x] = -1;


		}
		else
			break;

	}

 

두가지를 반복하며 결과를 추론해갑니다.

 

 

꼼꼼하게 조건을 따져보고 미리 설계를 정확하게 해야 쉽게 풀 수있습니다.

그리고 물고기 이동 후 미리 결과를 돌려보며 정확하게 행동하는지도 비교해야 합니다.

 

정답코드입니다.

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

typedef struct {
	int y, x;
	int dir;
	bool alive;
}fish;

int result = 0;
int y_ar[9] = {0, -1, -1, 0, 1, 1, 1, 0, -1};
int x_ar[9] = {0, 0, -1, -1, -1, 0, 1, 1, 1};
bool ended = false;


void dfs(fish a[17], fish b, int c[4][4],int cnt) {
	
	result = max(result, cnt);

	fish fishes[17];
	fish shark;
	int arr[4][4];

	for (int i = 1; i <= 16; i++)
		fishes[i] = a[i];
	shark = b;
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			arr[i][j] = c[i][j];




	// fish
	for (int i = 1; i <= 16; i++) {
		if (fishes[i].alive== false)
			continue;
		int y = fishes[i].y;
		int x = fishes[i].x;
		int dir = fishes[i].dir;

		int ny = y + y_ar[dir];
		int nx = x + x_ar[dir];
		bool jud = false;

		if (ny >= 0 && ny < 4 && nx >= 0 && nx < 4) {
			if (arr[ny][nx] == 0) { //없으면

				jud = true;
				fishes[i].y = ny;
				fishes[i].x = nx;
				arr[ny][nx] = i;
				arr[y][x] = 0;
				
			}
			else if (arr[ny][nx] != -1) {// 물고기가 있으면
				jud = true;
			
				fish temp = fishes[i];
				fishes[i].y = fishes[arr[ny][nx]].y;	
				fishes[i].x = fishes[arr[ny][nx]].x;
				fishes[arr[ny][nx]].y = temp.y;
				fishes[arr[ny][nx]].x = temp.x;

				int temp2;
				temp2 = arr[y][x];
				arr[y][x] = arr[ny][nx];
				arr[ny][nx] = temp2;

			}


		}
		if (jud == true) continue;
		else {
			int ndir = dir + 1;
			if (ndir == 9) ndir = 1;
			int ny = y + y_ar[ndir];
			int nx = x + x_ar[ndir];


			while (ndir != dir) {
				if (ny >= 0 && ny < 4 && nx >= 0 && nx < 4) {
					if (arr[ny][nx] == 0) { //없으면

						
						fishes[i].y = ny;
						fishes[i].x = nx;
						fishes[i].dir = ndir;
						arr[ny][nx] = i;
						arr[y][x] = 0;

						break;
					}
					else if (arr[ny][nx] != -1) {// 물고기가 있으면
						
						fish temp = fishes[i];
						fishes[i].y = fishes[arr[ny][nx]].y;
						fishes[i].x = fishes[arr[ny][nx]].x;
						fishes[arr[ny][nx]].y = temp.y;
						fishes[arr[ny][nx]].x = temp.x;
						

						int temp2;
						temp2 = arr[y][x];
						arr[y][x] = arr[ny][nx];
						arr[ny][nx] = temp2;

						fishes[i].dir = ndir;
						break;

					}

				}
				ndir++;
				if (ndir == 9) ndir = 1;
				ny = y + y_ar[ndir];
				nx = x + x_ar[ndir];

			}
		}



	}



	// 상어의 이동
	//1. 해당 방향으로 이동 (가능한 경우 모두)	
	
	int nx = shark.x;
	int ny = shark.y;

	while (1) {

		ny += y_ar[shark.dir];
		nx += x_ar[shark.dir];

		if (ny >= 0 && ny < 4 && nx >= 0 && nx < 4) {


			//1. 상어의 위치 바꾸기 2. 그 위치에 물고기
			if (arr[ny][nx] == 0) continue;


			int fishnum = arr[ny][nx];
			int ndir = fishes[fishnum].dir;

			arr[shark.y][shark.x] = 0;
			arr[ny][nx] = -1;
			shark = fishes[fishnum];
			fishes[fishnum].alive = false;


			dfs(fishes, shark, arr, cnt + fishnum);

			fishes[fishnum].alive = true;
			arr[ny][nx] = fishnum;
			shark = b;
			arr[shark.y][shark.x] = -1;


		}
		else
			break;

	}



}

int main() {
	int a, b;

	fish fishes[17];
	fish shark;
	int arr[4][4];
	int fishnum;

	for(int i=0;i<4;i++)
		for (int j = 0; j < 4; j++) {
			cin >> a >> b;
			if (i == 0 && j == 0) {
				shark = { i,j,b,1 };
				fishes[a] = { 0,0,0,0 };
				arr[0][0] = -1;
				fishnum = a;
				continue;
			}
			else{
				fishes[a] = { i,j,b,1 };
				arr[i][j] = a;
				}
		}



	dfs(fishes, shark, arr, fishnum);

	cout << result << endl;

}
반응형
반응형

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

 

1261번: 알고스팟

첫째 줄에 미로의 크기를 나타내는 가로 크기 M, 세로 크기 N (1 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 미로의 상태를 나타내는 숫자 0과 1이 주어진다. 0은 빈 방을 의미하고, 1은 벽을 의미

www.acmicpc.net

 

bfs문제인데 조금 꼬아놓은 bfs였습니다! 

최단 경로이동이 아니라 벽을 최소로 부수며 이동할때의 벽을 최소 몇 개 부수어야 하는지이기 때문에 방문 배열이 총 2개가 필요합니다.

 

1. 방문했는지 여부를 판단해주는 배열

2. 방문했다면 해당 경로로 최소 몇번만에 도달할 수 있는 표시하는 배열

 

쉬운문제였기 때문에 바로 정답코드입니다.

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

int m, n;
int arr[101][101] = { 0, };
int visited[101][101][2] = { 0, };

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

void bfs() {

	queue <pair<int, int>> que;
	que.push(make_pair(1, 1));
	if (arr[1][1] == 1) visited[1][1][0] = 1, visited[1][1][1] = 1;
	else visited[1][1][0] = 1, visited[1][1][1] = 0;

	while (!que.empty()) {

		int yy = que.front().first;
		int xx = que.front().second;
		que.pop();

		for (int i = 0; i < 4; i++) {
			int y = yy + y_ar[i];
			int x = xx + x_ar[i];

			if (y >= 1 && y <= n && x >= 1 && x <= m) {
				if (visited[y][x][0] == 0) { //방문한적 없어
					visited[y][x][0] = 1, visited[y][x][1] = visited[yy][xx][1] + arr[y][x];
					que.push(make_pair(y, x));	
				}
				else { // 방문했다면, 
					if (visited[y][x][1] > (visited[yy][xx][1] + arr[y][x])) { 
						visited[y][x][0] = 1, visited[y][x][1] = visited[yy][xx][1] + arr[y][x];
						que.push(make_pair(y, x));
					}
					

				}
			}

		}

	}

}

int main() {
	cin >> m >> n;
	for (int i = 1; i <= n; i++){
			string temp;
			cin >> temp;
			for (int j = 1; j <= m; j++)
				arr[i][j] = temp.at(j - 1) - '0';
	}

	
	bfs();

	
	cout << visited[n][m][1] << "\n";
}

 visited[yy][xx][1] + arr[y][x]는 지금까지 벽을 부순횟수 더하기 현재 벽이 있다면 부수고 들어가고(+1) 아니면(+0)을 하는 코드입니다. 

 

 

반응형

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

[백준] 1697- 숨바꼭질(C++)  (0) 2021.03.13
[백준] 2606- 바이러스(C++)  (0) 2021.02.06
[백준] 9019-DSLR  (0) 2020.08.10
[백준] 6593-상범 빌딩(C++)  (0) 2020.07.03
[백준] 4179-불!(C++)  (0) 2020.05.06

+ Recent posts