Posts 18500 미네랄 2
Post
Cancel

18500 미네랄 2

알고리즘

  • 2933 미네랄과 상당히 유사한 문제이지만, “분리된 클러스터의 각 열중 맨 아래 부분이 아닌 부분이 다른 클러스터 위에 떨어질 수 있다”라는 조건을 하나 더 생각해야함.
  • 막대를 던지고 클러스터가 분리되면 바닥에 닿았는지 판단.
  • 닿지 않았다면 아래로 내리는데, 내려갈 수 있는 미네랄을 다 검사.
  • 가장 적게 내려갈 수 있는 거리만큼 클러스터를 내림.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;

int R, C, listIdx;
char map[101][101];
int offset[4][2] = { {-1, 0}, {0,1}, {1, 0}, {0, -1} };
bool visit[101][101];
pair<int, int> l[10010];

void throwStick(int h, bool toRight);
bool isTouchFloor(int h, int w);
void downCluster();

int main() {
	string t;
	cin >> R >> C;
	for (int i = 0; i < R; i++) {
		cin >> t;
		for (int j = 0; j < C; j++) {
			map[i][j] = t[j];
		}
	}

	int n, input;
	bool toRight = true;
	cin >> n;
	while (n--) {
		cin >> input;
		throwStick(input, toRight);
		toRight = !toRight;
	}
	for (int i = 0; i < R; i++) {
		for (int j = 0; j < C; j++)
			cout << map[i][j];
		cout << endl;
	}
}

// 던지고 맞으면, 맞은 거부터 상하좌우 검색하여 클러스터 찾고 내리기.
void throwStick(int h, bool toRight) {
	bool hit = false;
	int w = 0;
	h = R - h;
	if (toRight) {
		for (int i = 0; i < C; i++)
			if (map[h][i] == 'x') {
				hit = true;
				w = i;
				break;
			}
	}
	else {
		for (int i = C - 1; i >= 0; i--)
			if (map[h][i] == 'x') {
				hit = true;
				w = i;
				break;
			}
	}

	if (!hit)
		return;

	map[h][w] = '.';

	for (int i = 0; i < 4; i++) {
		int ho = h + offset[i][0], wo = w + offset[i][1];
		if (ho >= 0 && ho < R && wo >= 0 && wo < C && map[ho][wo] == 'x') {
			if (!isTouchFloor(ho, wo))
				downCluster();
			for (int i = 0; i < listIdx; i++)
				visit[l[i].first][l[i].second] = false;
			listIdx = 0;
		}
	}
}


bool isTouchFloor(int h, int w) {
	int curIdx = 0;
	listIdx = 0;
	l[listIdx++] = { h,w };
	visit[h][w] = true;

	bool touch = false;

	while (curIdx != listIdx) {
		int h = l[curIdx].first, w=l[curIdx].second;
		curIdx++;

		if (h == R - 1) {
			touch = true;
			break;
		}

		for (int i = 0; i < 4; i++) {
			int ho = h + offset[i][0], wo = w + offset[i][1];
			if (!visit[ho][wo] && ho >= 0 && ho < R && wo >= 0 && wo < C && map[ho][wo] == 'x') {
				l[listIdx++] = { ho, wo };
				visit[ho][wo] = true;
			}
		}
	}

	if (touch)
		return true;
	return false;
}

//밑에 딴게 없는 것만 검사 -> 몇칸 내려가면 되는지 추산하기

void downCluster() {
	sort(&l[0], &l[listIdx]);
	int minDistance = 2000000000;

	for (int s = listIdx - 1; s >= 0; s--) {
		if (map[l[s].first + 1][l[s].second] != 'x') {
			int fromH = l[s].first + 1;
			for (; fromH < R; fromH++) {
				if (map[fromH][l[s].second] == 'x') {
					if (visit[fromH][l[s].second])
						fromH = 2000000000;
					break;
				}
			}
			minDistance = min(minDistance, fromH - l[s].first -1);

		}
	}
	for (int s = listIdx - 1; s >= 0; s--) {
		map[l[s].first + minDistance][l[s].second] = 'x';
		map[l[s].first][l[s].second] = '.';
	}
}
This post is licensed under CC BY 4.0 by the author.

10021 watering the field

16639 괄호 추가하기 3

Comments powered by Disqus.