반응형

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

 

17144번: 미세먼지 안녕!

미세먼지를 제거하기 위해 구사과는 공기청정기를 설치하려고 한다. 공기청정기의 성능을 테스트하기 위해 구사과는 집을 크기가 R×C인 격자판으로 나타냈고, 1×1 크기의 칸으로 나눴다. 구사

www.acmicpc.net

#include <bits/stdc++.h>
using namespace std;

int r, c, t, arr[51][51], cleaner;
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };


struct Dust {
	int x, y, q;
};


int ans() {
	int cnt = 0;
	for (int i = 0; i < r; i++) {
		for (int j = 0; j < c; j++) {
			if (arr[i][j] > 0) {
				cnt += arr[i][j];
			}
		}
	}
	return cnt;
}


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

	cin >> r >> c >> t;


	for (int i = 0; i < r; i++) {
		for (int j = 0; j < c; j++) {
			cin >> arr[i][j];
			if (arr[i][j] == -1) {
				cleaner = i;
			}
		}
	}

	int clean_up = cleaner - 1;
	int clean_down = cleaner;

	//1.미세먼지 확산
	//2. 공기 청정기 이동 
	for (int T = 1; T <= t; T++) {

		vector<Dust> d;

		for (int i = 0; i < r; i++) {
			for (int j = 0; j < c; j++) {
				if (arr[i][j] >= 5) {
					d.push_back({ i,j,arr[i][j] });
				}
			}
		}

		//확산 
		for (int i = 0; i < d.size(); i++) {
			int spread = 0;
			if (d[i].q >= 5) {
				for (int k = 0; k < 4; k++) {
					int nx = d[i].x + dx[k];
					int ny = d[i].y + dy[k];

					if (nx < 0 || nx >= r || ny < 0 || ny >= c) continue;
					if (arr[nx][ny] == -1)continue;
					arr[nx][ny] += (d[i].q / 5);
					spread++;

				}
				arr[d[i].x][d[i].y] -= (d[i].q / 5) * spread;
			}
		}

		// 공기청정기 작동 
		for (int i = clean_up - 1; i >= 0; i--) {
			arr[i + 1][0] = arr[i][0];
		}

		for (int i = clean_down; i < r; i++) {
			arr[i][0] = arr[i + 1][0];

		}

		for (int i = 0; i < c-1; i++) {
			arr[0][i] = arr[0][i + 1];
			arr[r - 1][i] = arr[r - 1][i + 1];
		}

		for (int i = 0; i < clean_up ; i++) {
			arr[i][c - 1] = arr[i + 1][c - 1];
		}

		for (int i = r-1; i > clean_down; i--) {
			arr[i][c - 1] = arr[i - 1][c - 1];
		}

		for (int i = c - 1; i > 1; i--) {
			arr[clean_up][i] = arr[clean_up][i - 1];
			arr[clean_down][i] = arr[clean_down][i - 1];
		}
		arr[clean_up][1] = 0;
		arr[clean_down][1] = 0;


		arr[clean_up][0] = -1;
		arr[clean_down][0] = -1;


	}

	int ans = 0;
	for (int i = 0; i < r; i++) {
		for (int j = 0; j < c; j++) {
			if (arr[i][j] > 0) ans += arr[i][j];
		}
	}

	cout << ans << '\n';

	return 0;
}

백준 17144번 미세먼지 안녕!

반응형
반응형

 

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

 

17143번: 낚시왕

낚시왕이 상어 낚시를 하는 곳은 크기가 R×C인 격자판으로 나타낼 수 있다. 격자판의 각 칸은 (r, c)로 나타낼 수 있다. r은 행, c는 열이고, (R, C)는 아래 그림에서 가장 오른쪽 아래에 있는 칸이다.

www.acmicpc.net

1. 문제설명

낚시왕이 되는 일은 꽤 어려운 일인지도 모릅니다.

 

백준 17143번 낚시왕

어부는 오른쪽 열로 한칸 씩 이동하면서 

어부가 서있는 열에서 가장 가까운 상어를 잡습니다.

 

상어는 어부가 한칸 움직일 때마다 각각의 방향과 속도로 움직입니다.

만약 모든 상어가 움직인 후 같은 칸에 상어가 두마리 있을 경우 크기가 큰 상어만 남습니다.

 

어부가 끝까지 이동한 후 잡은 상어의 크기 합을 출력하면 됩니다.

 


2.접근방법[알고리즘]

이 문제를 해결하기 위해 특별히 필요한 알고리즘은 없습니다.

 

문제에서 제시한 조건 대로 구현하면 됩니다.

 

1. 어부가 오른쪽 열로 한칸 움직이고 가장 가까운 상어를 잡는다.

2. 상어 모두 각각 움직인다.

3. 겹치는 상어가 있으면 크기가 큰 것만 남긴다.

 

상어의 움직임을 구현하는 게 이 문제의 핵심입니다.

 

Input

상어의 정보는 다섯 정수 r, c, s, d, z (1 ≤ r ≤ R, 1 ≤ c ≤ C, 0 ≤ s ≤ 1000, 1 ≤ d ≤ 4, 1 ≤ z ≤ 10000) 로 이루어져 있다. (r, c)는 상어의 위치, s는 속력, d는 이동 방향, z는 크기이다.

 

전체 격자판 최대 크기는 100*100인데

상어의 속도는 1000이 최댓값이기 때문에

1000을 그대로 사용한다면 불필요한 움직임이 많이 포함됩니다.

 

상어가 열이나 행을 왕복하는데 필요한 거리는 r, c 값에 따라 고정되어 있기 때문에

연산을 통해 속도를 빼줄 수 있습니다.

if (d <= 2) s %= (r - 1) * 2;
else s %= (c - 1) * 2;

(r-1)*2 번이나 (c-1)*2 번 왔다갔다 하면 상어가 제자리에 놓이기 때문에

불필요한 연산을 줄여줄 수 있습니다.

이 과정을 거치지 않으면 시간초과가 납니다.

 

 

 


3.문제풀이코드 C++

 

#include <bits/stdc++.h>
using namespace std;

int r, c, m, ans;

struct Shark {
	bool isin = 0;
	int s = 0, d = 0, z = 0;
};

Shark ch[103][103];

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

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

	cin >> r >> c >> m;
	for (int i = 0; i < m; i++) {
		int a, b, s, d, z;
		cin >> a >> b >> s >> d >> z;

		//상어의 반복움직임 제거
		if (d <= 2) s %= (r - 1) * 2;
		else s %= (c - 1) * 2;

		ch[a][b] = { 1,s,d,z };
	}


	for (int i = 1; i <= c; i++) {

		Shark moved[103][103];

		//해당 열에서 상어 잡기 
		for (int j = 1; j <= r; j++) {
			if (ch[j][i].isin) {
				ans += ch[j][i].z;
				ch[j][i] = { 0,0,0,0 };
				break;
			}
		}

		// 상어 이동 
		for (int j = 1; j <= r; j++) {
			for (int k = 1; k <= c; k++) {
				if (ch[j][k].isin) {
					int nx = j;
					int ny = k;

					for (int q = 0; q < ch[j][k].s; q++) {
						if (ch[j][k].d == 1) {
							//벽 만난 경우 방향전환
							if (nx == 1) {
								ch[j][k].d = 2;
								q--;
								continue;
							}
							nx += dx[0];
							ny += dy[0];

						}
						else if (ch[j][k].d == 2) {
							if (nx == r) {
								ch[j][k].d = 1;
								q--;
								continue;
							}

							nx += dx[1];
							ny += dy[1];

						}
						else if (ch[j][k].d == 3) {
							if (ny == c) {
								ch[j][k].d = 4;
								q--;
								continue;
							}
							nx += dx[2];
							ny += dy[2];

						}
						else if (ch[j][k].d == 4) {
							if (ny == 1) {
								ch[j][k].d = 3;
								q--;
								continue;
							}
							nx += dx[3];
							ny += dy[3];
						}

					}
					// 같은 칸에 상어 두마리가 있는 경우
					// 크키가 큰 상어만 남긴다.
					if (moved[nx][ny].isin) {
						if (moved[nx][ny].z < ch[j][k].z) {
							moved[nx][ny] = { 1,ch[j][k].s,ch[j][k].d,ch[j][k].z };
						}
					}
					else {
						moved[nx][ny] = { 1,ch[j][k].s,ch[j][k].d,ch[j][k].z };
					}

				}
			}
		}
		// moved 배열에 있는 값을 ch배열로 복사해주고 
		// ch배열을 통해 어부가 이동한후 다시 계산하도록 해준다.
		memcpy(&ch, &moved, sizeof(moved));
	}

	cout << ans << '\n';
	return 0;
}

백준 17143번 낚시왕

 

 

백준 17143번 낚시왕 테스트케이스 및 반례

50 50 19
4 9 21 1 999
50 50 4 4 500
50 49 222 3 200
50 48 12 2 45
50 47 36 1 900
2 3 20 3 444
4 8 4 2 49
3 3 40 4 50
2 2 460 2 4444
48 23 500 3 12
1 1 200 1 123
44 44 123 3 125
44 40 222 3 17
40 44 333 3 57
18 40 1 1 4
3 10 50 2 406
1 36 177 4 50
1 46 120 4 7
1 50 28 4 54
정답 7718

 

반응형
반응형

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

 

14890번: 경사로

첫째 줄에 N (2 ≤ N ≤ 100)과 L (1 ≤ L ≤ N)이 주어진다. 둘째 줄부터 N개의 줄에 지도가 주어진다. 각 칸의 높이는 10보다 작거나 같은 자연수이다.

www.acmicpc.net

1.문제설명

백준 14890번

갈 수 있는 길인지 판단하고(한 줄의 모든 숫자가 같은 지),

경사로를 둬서 갈 수 있는 길로 만들 수 있는지 확인해야한다.

 

 


 

2.접근방법[알고리즘]

 

먼저 모든 숫자가 같은지 확인하고,

모든 숫자가 같지 않다면

 

경사로를 둬서 갈 수 있는 길인지 확인하기 위해서

각 행을 해당 숫자와 해당 숫자의 개수로 표현했다.

 

6 2
3 3 3 3 3 3
2 3 3 3 3 3
2 2 2 3 2 3
1 1 1 2 2 2
1 1 1 3 3 1
1 1 2 3 3 2

이런 입력의 경우 가로 행만 살펴보면

6 2                 Num : Count
3 3 3 3 3 3        -> 3 : 6
2 3 3 3 3 3           2 : 1 , 3 : 5
2 2 2 3 2 3           2 : 3, 3 : 1 , 2 : 1 , 3 : 1
1 1 1 2 2 2           1 : 3, 2 : 3
1 1 1 3 3 1           1 : 3 , 3 : 2 , 1 : 1 
1 1 2 3 3 2           1 : 2, 2 : 1 , 3 : 2 , 2 : 1

이렇게 표현 할 수 있다

이렇게 한 줄에 대한 정보를 표현하고

L 변수를 이용해서 경사로를 둘 수 있는 지 없는 지 판단 할 수 있다

 

L = 2 일 때

3 : 6 은 모두 같은 숫자이므로 길이다.

 

2 : 1 , 3 : 5

이 줄에는 경사로를 둬서 길을 만들 수 없다.

숫자가 작은 부분의 길이가 L보다 작기 때문이다.

 

2 : 3 , 3 : 1, 2 :1 , 3: 1

이 줄도 2:1 이므로 2의 길이가 L보다 작으므로 길이 될 수 없다

 

1 : 3 , 2 : 3

1의 길이가 3이므로 L보다 커서 길이 될 수 있다.

 

 

 

예외

L이 동일하게 2일 때

 

3 3 2 2 3 3

이런 경우는 2에 경사로를 한 번 두면 더이상 경사로를 또 둘 수 없기 때문에 길이 될 수 없다.

 

 

 

이러한 경우들을 코드로 구현해보면

 

void Count(int arr[101][101]) {
	for (int i = 1; i <= n; i++) {
		int val = 0, cnt = 0;
		
        //v 벡터에 한 줄 정보 표현 
		vector<pair<int, int> > v;
		for (int j = 1; j <= n; j++) {
			if (j == 1) {
				val = arr[i][j];
				cnt = 1;
				continue;
			}

			if (arr[i][j] == val) {
				cnt++;
			}
			else {
				v.push_back({ val,cnt });
				val = arr[i][j];
				cnt = 1;
			}
		}
		v.push_back({ val,cnt });
		
        // 모두 같은 숫자인 경우 
		if (v.size() == 1) {
			ans++;
			continue;
		}

		//경사로 추가해서 길을 만들 수 있는지 확인 
		bool canmake = true;

		for (int k = 0; k < v.size() - 1; k++) {
        	// 높이 차이가 1보다 크면 길이 될 수 없다.
			if (abs(v[k].first - v[k + 1].first) > 1) {
				canmake = false;
				break;
			}


			if (v[k].first < v[k + 1].first) {
				if (v[k].second < l) {
					canmake = false;
					break;
				}
			}
			else {
				if (v[k + 1].second < l) {
					canmake = false;
					break;
				}
				else {
                	// 332233 같은 경우를 위해 경사로를 두면 count에서 빼준다.
					v[k + 1].second -= l;
				}

			}
		}
		if (canmake) ans++;
	}

}

 


 

3.문제풀이코드 C++

#include <bits/stdc++.h>
using namespace std;

int n, l, arr[101][101], arr2[101][101], ans;

void Count(int arr[101][101]) {
	for (int i = 1; i <= n; i++) {
		int val = 0, cnt = 0;

		vector<pair<int, int> > v;
		for (int j = 1; j <= n; j++) {
			if (j == 1) {
				val = arr[i][j];
				cnt = 1;
				continue;
			}

			if (arr[i][j] == val) {
				cnt++;
			}
			else {
				v.push_back({ val,cnt });
				val = arr[i][j];
				cnt = 1;
			}
		}
		v.push_back({ val,cnt });

		if (v.size() == 1) {
			ans++;
			continue;
		}

		//경사로 추가해서 길을 만들 수 있는지 확인 
		bool canmake = true;

		for (int k = 0; k < v.size() - 1; k++) {
			if (abs(v[k].first - v[k + 1].first) > 1) {
				canmake = false;
				break;
			}

			if (v[k].first < v[k + 1].first) {
				if (v[k].second < l) {
					canmake = false;
					break;
				}
			}
			else {
				if (v[k + 1].second < l) {
					canmake = false;
					break;
				}
				else {
					v[k + 1].second -= l;
				}

			}
		}
		if (canmake) ans++;
	}

}

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

	cin >> n >> l;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			cin >> arr[i][j];
			arr2[j][i] = arr[i][j];
		}
	}
	
	Count(arr);
	Count(arr2);


	cout << ans << '\n';


	return 0;

}

14890번 경사로

 

이 문제에서 가로방향 길과 세로방향 길의 개수를 모두 세야한다.

 

하지만 가로방향이나 세로방향이나 길을 세는 방법이 동일하기 때문에

 

arr2 배열을 arr과 대칭적으로 입력해주어 동일하게 Count 하면

 

쉽게 답을 구할 수 있다.

반응형
반응형

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

 

11724번: 연결 요소의 개수

첫째 줄에 정점의 개수 N과 간선의 개수 M이 주어진다. (1 ≤ N ≤ 1,000, 0 ≤ M ≤ N×(N-1)/2) 둘째 줄부터 M개의 줄에 간선의 양 끝점 u와 v가 주어진다. (1 ≤ u, v ≤ N, u ≠ v) 같은 간선은 한 번만 주

www.acmicpc.net

1. 문제설명

무방향 그래프가 주어지고 노드와 간선간의 정보가 주어졌을 때

연결 요소 (Connected Component)의 개수를 구하는 문제입니다.

 

연결 요소의 개수는

서로 연결되어 있는 집합이 몇개인 지 구해야 합니다.

 

Connected Component

 

위 그림과 같은 경우 Connected Component는 2개 입니다.

 

 

 

2.접근방법[알고리즘]

 

먼저 떠오르는 해결 방법은

모든 노드 간선 정보를 바탕으로 그래프를 만들고

BFS나 DFS로 탐색하면서 방문한 노드를 체크하면서

방문하지 않은 새로운 노드를 발견할 때마다 정답으로 출력할 변수에 +1을 해주면 구할 수 있습니다.

 

 

한번 더 나아가면 Union & Find 알고리즘을 이용해

서로 연결되어있는 노드는 같은 집합으로 분류해주고

부모노드의 개수를 세면 집합의 개수를 알 수 있습니다.

Union & Find 알고리즘을 이용하면 BFS나 DFS보다 시간을 절약해서 풀 수 있습니다.

 

 

 

3.문제풀이코드 C++

 

1. Union & Find C++

#include <bits/stdc++.h>
using namespace std;

int n, m , unf[1001], ans;

int Find(int a) {
	if (a == unf[a]) {
		return a;
	}
	else {
		return unf[a] = Find(unf[a]);
	}
}

void Union(int a, int b) {
	a = Find(a);
	b = Find(b);

	if (a > b) {
		swap(a, b);
	}

	if (a != b) {
		unf[a] = b;
	}
}

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

	cin >> n >> m;

	for (int i = 0; i <= 1000; i++) {
		unf[i] = i;
	}

	for (int i = 0; i < m; i++) {
		int a, b;
		cin >> a >> b;
		Union(a, b);
	}

	// 부모 노드의 개수 == 같은 집합의 개수
	for (int i = 1; i <= n; i++) {
		if (unf[i] == i) ans++;
	}
	cout << ans << '\n';



	return 0;

}

11724 Union&amp;Find

 

 

2. BFS

#include <bits/stdc++.h>
using namespace std;

int n, m;

bool ch[1001];
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> m;

	vector<int> map[1001];

	for (int i = 0; i < m; i++) {
		int a, b;
		cin >> a >> b;

		map[a].push_back(b);
		map[b].push_back(a);
	}
	int ans = 0;
	queue<int> Q;
	for (int i = 1; i <= n; i++) {
		if (!ch[i]) {
			ans++;
			ch[i] = 1;
			Q.push(i);
			while (!Q.empty()) {
				int x = Q.front();
				Q.pop();
				for (int j = 0; j < map[x].size(); j++) {
					if (ch[map[x][j]] == 0) {
						ch[map[x][j]] = 1;
						Q.push(map[x][j]);
					}
				}
			}
		}
	}

	cout << ans << '\n';

	return 0;

}

11724 BFS

 

 

 

 

 

반응형
반응형

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

 

14888번: 연산자 끼워넣기

첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수, 

www.acmicpc.net

 

 

#include <bits/stdc++.h>
using namespace std;

int n, arr[12], op[4], max_ans = INT_MIN, min_ans = INT_MAX;

void DFS(int x, int res) {

	if (x == n - 1) {
		max_ans = max(max_ans,res);
		min_ans = min(min_ans,res);
	}

	for (int i = 0; i < 4; i++) {
		if (op[i] > 0) {
			op[i]--;

			if (i == 0) {
				DFS(x + 1, res + arr[x + 1]);
			}
			else if (i == 1) {
				DFS(x + 1, res - arr[x + 1]);

			}
			else if (i == 2) {
				DFS(x + 1, res * arr[x + 1]);

			}
			else if (i == 3) {
				DFS(x + 1, res / arr[x + 1]);
			}
			op[i]++;
		}
	}

}


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


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

	for (int i = 0; i < 4; i++) {
		cin >> op[i];
	}

	DFS(0, arr[0]);

	cout << max_ans << '\n';
	cout << min_ans << '\n';


	return 0;
	
}

백준 14888번 연산자끼워넣기

반응형
반응형

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

 

16235번: 나무 재테크

부동산 투자로 억대의 돈을 번 상도는 최근 N×N 크기의 땅을 구매했다. 상도는 손쉬운 땅 관리를 위해 땅을 1×1 크기의 칸으로 나누어 놓았다. 각각의 칸은 (r, c)로 나타내며, r은 가장 위에서부터

www.acmicpc.net

1.문제설명

 

봄에는 나무가 자신의 나이만큼 양분을 먹고, 나이가 1 증가한다. 각각의 나무는 나무가 있는 1×1 크기의 칸에 있는 양분만 먹을 수 있다. 하나의 칸에 여러 개의 나무가 있다면, 나이가 어린 나무부터 양분을 먹는다. 만약, 땅에 양분이 부족해 자신의 나이만큼 양분을 먹을 수 없는 나무는 양분을 먹지 못하고 즉시 죽는다.

 

여름에는 봄에 죽은 나무가 양분으로 변하게 된다. 각각의 죽은 나무마다 나이를 2로 나눈 값이 나무가 있던 칸에 양분으로 추가된다. 소수점 아래는 버린다.

가을에는 나무가 번식한다. 번식하는 나무는 나이가 5의 배수이어야 하며, 인접한 8개의 칸에 나이가 1인 나무가 생긴다.

 

겨울에는 S2D2가 땅을 돌아다니면서 땅에 양분을 추가한다. 각 칸에 추가되는 양분의 양은 A[r][c]이고, 입력으로 주어진다.

 

문제에서 설명한 단계에 맞춰서 똑같이 구현하면 됩니다.

 


2.접근방법[알고리즘]

구현과 동시에 코드 최적화가 핵심입니다.

시간제한이 0.3초여서 최대한 최적화해야 해결할 수 있습니다.

 

이 문제에서 한 칸 안에 나무 여러 개가 있을 수 있습니다.

한 칸에 나무가 여러 개 있을 경우 나이가 적은 나무 부터 양분을 섭취해야합니다.

 

이때 자연스럽게 매번마다 나무를 오름차순으로 sort한 뒤 양분을 섭취하게끔 해야겠다는 생각이 듭니다.

하지만 그러면 시간초과로 틀립니다.

 

문제 조건 상 sort는 맨 처음 한 번만 해도 풀 수 있습니다.

 

8칸에 새로 생기는 나무의 나이는 무조건 1이기 때문에

새로 생긴 나무를 맨 앞으로 보내주고

이전에 있던 나무들은 뒤로 보내주면 sort를 해주지 않아도 됩니다.

 


 

3.문제풀이코드 C++

#include <bits/stdc++.h>
using namespace std;

int n, m, k, ans, arr[11][11], added[11][11];
int dx[8] = { 1,0,-1,0,1,-1,1,-1 };
int dy[8] = { 0,1,0,-1,1,-1,-1,1 };

struct Tree {
	int x, y, age;
	bool operator<(const Tree &bb) const {
		return age < bb.age;
	}
};

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

	vector<Tree> v;
	cin >> n >> m >> k;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			cin >> added[i][j];
			arr[i][j] = 5;
		}
	}

	for (int i = 0; i < m; i++) {
		int x, y, z;
		cin >> x >> y >> z;
		v.push_back({ x,y,z });
	}

	sort(v.begin(), v.end());
	
	for (int K = 0; K < k; K++) {
		vector<Tree> new_v;

		// 봄
		for (int i = 0; i < v.size(); i++) {
			if (v[i].age == 0) continue;

			if (v[i].age <= arr[v[i].x][v[i].y]) {
				arr[v[i].x][v[i].y] -= v[i].age;
				v[i].age++;

				// 가을에 새로 생기는 나무들
				if (v[i].age % 5 == 0) {
					for (int j = 0; j < 8; j++) {
						int nx = v[i].x + dx[j];
						int ny = v[i].y + dy[j];
                        
						//new_v 벡터에 새로생기는 나무들 먼저 넣어줌
						if (nx <= 0 || nx > n || ny <= 0 || ny > n)continue;
						new_v.push_back({ nx, ny, 1 });
					}
				}
			}
			else {
            	//죽은 나무들 
				v[i].age = -v[i].age;
			}
		}

		//여름 
		for (int i = 0; i < v.size(); i++) {
        //죽은 나무들 양분으로 전환 
			if (v[i].age < 0)
			{
				arr[v[i].x][v[i].y] += (-v[i].age / 2);
			}
			else {
            //new_v에 기존에 있던 나무들 뒤로 보내줌 
				new_v.push_back(v[i]);
			}
		}

		// 겨울
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				arr[i][j] += added[i][j];
			}
		}

		v.swap(new_v);
	}


	cout << v.size() << '\n';
	return 0;
	
}

백준 16235번 시간초과 해결

 

 

 

백준 16235번: 나무 재테크 반례

이 테스트케이스가 오래 걸린다면 통과할 수 없습니다.

10 100 1000
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
1 1 4
1 2 4
1 3 4
1 4 4
1 5 4
1 6 4
1 7 4
1 8 4
1 9 4
1 10 4
2 1 4
2 2 4
2 3 4
2 4 4
2 5 4
2 6 4
2 7 4
2 8 4
2 9 4
2 10 4
3 1 4
3 2 4
3 3 4
3 4 4
3 5 4
3 6 4
3 7 4
3 8 4
3 9 4
3 10 4
4 1 4
4 2 4
4 3 4
4 4 4
4 5 4
4 6 4
4 7 4
4 8 4
4 9 4
4 10 4
5 1 4
5 2 4
5 3 4
5 4 4
5 5 4
5 6 4
5 7 4
5 8 4
5 9 4
5 10 4
6 1 4
6 2 4
6 3 4
6 4 4
6 5 4
6 6 4
6 7 4
6 8 4
6 9 4
6 10 4
7 1 4
7 2 4
7 3 4
7 4 4
7 5 4
7 6 4
7 7 4
7 8 4
7 9 4
7 10 4
8 1 4
8 2 4
8 3 4
8 4 4
8 5 4
8 6 4
8 7 4
8 8 4
8 9 4
8 10 4
9 1 4
9 2 4
9 3 4
9 4 4
9 5 4
9 6 4
9 7 4
9 8 4
9 9 4
9 10 4
10 1 4
10 2 4
10 3 4
10 4 4
10 5 4
10 6 4
10 7 4
10 8 4
10 9 4
10 10 4

 8456​

 

반응형
반응형

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

 

17140번: 이차원 배열과 연산

첫째 줄에 r, c, k가 주어진다. (1 ≤ r, c, k ≤ 100) 둘째 줄부터 3개의 줄에 배열 A에 들어있는 수가 주어진다. 배열 A에 들어있는 수는 100보다 작거나 같은 자연수이다.

www.acmicpc.net

 

1.문제설명

 

백준 17140번

 

문제에서 R연산과 C연산을 하는 방법을 설명합니다.

초기에 입력으로 주어진 배열로

R연산이나 C연산을 거듭하면서 주어진 조건에 부합하면 종료하면 됩니다.

 

 


 

2.접근방법[알고리즘]

 

입력

1 2 3
1 2 1
2 1 3
3 3 3

출력

2

백준 17140번 이차원 배열과 연산 

 

정렬방법

문제에서 주어지는 정렬 방법 대로 조건을 만족할 때 까지

계속 정렬하고 배열에 넣고 정렬하고 배열에 넣고 반복해야합니다.

 

[1, 2 , 3] 정렬 방법은

 

숫자 1 : 1개 {1 : 1}

숫자 2 : 1개 {2 : 1}

숫자 3 : 1개 {3 : 1}

 

문제 조건이 "수의 등장 횟수가 커지는 순으로, 그러한 것이 여러가지면 수가 커지는 순으로 정렬한다." 이므로 

{1 : 1} , { 2 : 1 } , { 3 : 1} 순으로 정렬되고 배열에 들어갈 때

1 1 2 1 3 1 이렇게 됩니다.

이 정렬 방법대로 R, C 연산을 계속 반복해야합니다.

 

정렬 구현 코드


for (int i = 1; i <= row; i++) {
    map<int, int> m;

    for (int j = 1; j <= col; j++) {
        if (arr[i][j] != 0) {
            m[arr[i][j]]++;
            arr[i][j] = 0;
        }
    }
    vector<pair<int, int> > v(m.begin(), m.end());

    sort(v.begin(), v.end(), comp);
    int p = 1;

    for (int j = 0; j < v.size(); j++) {
        if (v[j].second == 0 || p>100) break;
        arr[i][p++] = v[j].first;
        arr[i][p++] = v[j].second;
    }
    maxp = max(p - 1, maxp);

}

맵과 벡터를 이용해서

맵으로 숫자 개수를 카운트하고 벡터에 pair 자료형으로 넣어준 뒤

문제 조건대로 정렬을 한 후 정렬 된 상태로 arr에 넣어줬습니다.

 

for문을 돌면서 행이나 열을 돌 때 갯수를 센 후 0으로 초기화 해주어야합니다.

초기화를 해주지 않으면 이전 배열의 숫자가 계속 누적되어 틀립니다.

 

 


 

3. 문제풀이코드 C++

#include <bits/stdc++.h>
using namespace std;

int arr[202][202], r, c, k, ans = INT_MAX;

bool comp(const pair<int, int>& a, const pair<int, int>& b) {
	if (a.second == b.second) return a.first < b.first;
	else return a.second < b.second;
}

void DFS(int row, int col, int trial) {

	if (trial > 100) {
		return;
	}
	if (arr[r][c] == k) {
		ans = min(ans, trial);
		return;
	}

	if (row >= col) {
		int maxp = 0;
		for (int i = 1; i <= row; i++) {
			map<int, int> m;

			for (int j = 1; j <= col; j++) {
				if (arr[i][j] != 0) {
					m[arr[i][j]]++;
					arr[i][j] = 0;
				}
			}
			vector<pair<int, int> > v(m.begin(), m.end());

			sort(v.begin(), v.end(), comp);
			int p = 1;

			for (int j = 0; j < v.size(); j++) {
				if (v[j].second == 0 || p>100) break;
				arr[i][p++] = v[j].first;
				arr[i][p++] = v[j].second;
			}
			maxp = max(p - 1, maxp);

		}

		DFS(row, maxp, trial + 1);
	}
	else {
		int maxp = 0;
		for (int i = 1; i <= col; i++) {
			map<int, int> m;

			for (int j = 1; j <= row; j++) {
				if (arr[j][i] != 0) {
					m[arr[j][i]]++;
					arr[j][i] = 0;
				}
			}
			vector<pair<int, int> > v(m.begin(), m.end());

			sort(v.begin(), v.end(), comp);
			int p = 1;
			for (int j = 0; j < v.size(); j++) {
				if (v[j].second == 0 || p>100) break;
				arr[p++][i] = v[j].first;
				arr[p++][i] = v[j].second;

			}
			maxp = max(p - 1, maxp);
		}

		DFS(maxp, col, trial + 1);
	}
}


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

	cin >> r >> c >> k;

	for (int i = 1; i <= 3; i++) {
		for (int j = 1; j <= 3; j++) {
			cin >> arr[i][j];
		}
	}

	DFS(3, 3, 0);

	if (ans == INT_MAX) {
		cout << -1 << '\n';
	}
	else cout << ans << '\n';
	return 0;
}

백준 17140 메모리 및 시간

 

반응형
반응형

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

 

14503번: 로봇 청소기

로봇 청소기가 주어졌을 때, 청소하는 영역의 개수를 구하는 프로그램을 작성하시오. 로봇 청소기가 있는 장소는 N×M 크기의 직사각형으로 나타낼 수 있으며, 1×1크기의 정사각형 칸으로 나누어

www.acmicpc.net

1.문제설명

d가 0인 경우에는 북쪽을, 1인 경우에는 동쪽을, 2인 경우에는 남쪽을, 3인 경우 서쪽을 나타낸다.

 

로봇 청소기는 다음과 같이 작동한다.

  1. 현재 위치를 청소한다.
  2. 현재 위치에서 현재 방향을 기준으로 왼쪽 방향부터 차례대로 인접한 칸을 탐색한다.
    1. 왼쪽 방향에 아직 청소하지 않은 공간이 존재한다면, 그 방향으로 회전한 다음 한 칸을 전진하고 1번부터 진행한다.
    2. 왼쪽 방향에 청소할 공간이 없다면, 그 방향으로 회전하고 2번으로 돌아간다.
    3. 네 방향 모두 청소가 이미 되어있거나 벽인 경우에는, 바라보는 방향을 유지한 채로 한 칸 후진을 하고 2번으로 돌아간다.
    4. 네 방향 모두 청소가 이미 되어있거나 벽이면서, 뒤쪽 방향이 벽이라 후진도 할 수 없는 경우에는 작동을 멈춘다.

방향을 전환하면서 이동하면서 청소를 할 수 있는 방의 개수를 찾아야 하는 문제다.

 

 

2.접근 방법[알고리즘]

이 문제를 DFS를 통해 시뮬레이션을 할 때 

종료 조건은 탐색할 수 있는 네 방향 모두 이미 청소되었거나 벽인 경우이고 후진을 할 수 없을 때다.

 

DFS를 돌면서 네방향 모두 체크해주고,

네방향 모두 이미 청소되었거나 벽이라면 

후진을 시켜주고 후진을 할 수 없다면 종료를 시켜준다.

 

종료조건에 해당하지 않는다면

방향전환을 하고, 방향전환시 전진 했을 때 청소가 가능한 방이라면 전진을 시켜준다.

청소가 불가능 한 방이라면 전진하지 않는다.

 

해당 좌표가 이미 방문했던 점이라도 다시 방문해도 상관 없다

위 조건에만 만족하면 된다.

 

DFS코드

void DFS(int x, int y, int d) {
	if (ended) return;
	bool all_cleaned = true;

	//네방향 확인 
	for (int i = 0; i < 4; i++) {
		if (arr[x + dx[i]][y + dy[i]] == 0) {
			all_cleaned = false;
			break;
		}
	}
	if (all_cleaned) {
		// 벽이 있어서 후진 할 수 없다면 종료
		if (arr[x - dx[d]][y - dy[d]] == -1) {
			ended = true;
			return;
		}
		else {
			//후진이 가능할 때
			DFS(x - dx[d], y - dy[d], d);
		}
	}
	// 왼쪽으로 방향 회전 
	int nd = d == 0 ? 3 : d - 1;
	int nx = x + dx[nd];
	int ny = y + dy[nd];

	if (arr[nx][ny] == 0) {
		arr[nx][ny] = ++cleaned;
        //청소 가능한 방이라면 방향전환후 전진
		DFS(nx, ny, nd);
	}
	else {
    	//청소 불가능한 방이라면 방향전환만 
		DFS(x, y, nd);
	}
}

 

 

3.문제풀이코드 C++

#include <bits/stdc++.h>
using namespace std;

int n, m, r, c, d, arr[51][51], cleaned;
int dx[4] = { -1,0,1,0 };
int dy[4] = { 0,1,0,-1 };
bool ended = false;

void DFS(int x, int y, int d) {
	if (ended) return;
	bool all_cleaned = true;

	//네방향 확인 
	for (int i = 0; i < 4; i++) {
		if (arr[x + dx[i]][y + dy[i]] == 0) {
			all_cleaned = false;
			break;
		}
	}
	if (all_cleaned) {
		// 벽이 있어서 후진 할 수 없다면 종료
		if (arr[x - dx[d]][y - dy[d]] == -1) {
			ended = true;
			return;
		}
		else {
			//후진이 가능할 때
			DFS(x - dx[d], y - dy[d], d);
		}
	}
	// 왼쪽으로 방향 회전 
	int nd = d == 0 ? 3 : d - 1;
	int nx = x + dx[nd];
	int ny = y + dy[nd];

	if (arr[nx][ny] == 0) {
		arr[nx][ny] = ++cleaned;
		DFS(nx, ny, nd);
	}
	else {
		DFS(x, y, nd);
	}
}


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

	cin >> n >> m;
	cin >> r >> c >> d;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cin >> arr[i][j];
			if (arr[i][j] == 1) {
				arr[i][j] = -1;
			}
		}
	}
	arr[r][c] = ++cleaned;
	DFS(r, c, d);
	cout << cleaned;
	return 0;
}

백준 14503번 메모리 및 시간

반응형

+ Recent posts