#include <iostream>
#include <queue>
#include <cstring>
#include <string>
using namespace std;
int h = 0, w = 0;
int visited[1000][1000] = { 0 };
char arr[1000][1000];
queue <int> fire[2];
queue <int> people[2];
int x_ar[4] = { -1,1,0,0 };
int y_ar[4] = { 0,0,1,-1 };
void bfs() {
//초기값 입력
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++)
if (arr[i][j] == 'F')
fire[0].push(i), fire[1].push(j);
else if (arr[i][j] == 'J')
people[0].push(i), people[1].push(j), visited[i][j] = 1;
while (!people[0].empty()) { //상근이가 이동할 경로가 없을 때 까지 반복
//1. 불먼저 전파
int fire_cnt = fire[0].size();
while (fire_cnt--) {
int yy = fire[0].front();
int xx = fire[1].front();
fire[0].pop(), fire[1].pop();
for (int i = 0; i < 4; i++) {
int y = yy + y_ar[i];
int x = xx + x_ar[i];
if (y >= 0 && y < h && x >= 0 && x < w)
if (arr[y][x] == '.' || arr[y][x] == 'J') {
arr[y][x] = 'F';
fire[0].push(y), fire[1].push(x);
}
}
}
//2. 상근좌 이동
int people_cnt = people[0].size();
while (people_cnt--) {
int yy = people[0].front();
int xx = people[1].front();
people[0].pop(), people[1].pop();
for (int i = 0; i < 4; i++) {
int y = yy + y_ar[i];
int x = xx + x_ar[i];
if (y >= 0 && y < h && x >= 0 && x < w)
if (arr[y][x] == '.' && visited[y][x] == 0) {
visited[y][x] = visited[yy][xx] + 1;
people[0].push(y), people[1].push(x);
}
}
}
}
//3. 모서리의 visited값들을 확인하고 결과값을 도출
int result = 1000000;
bool alive = false;
for (int i = 0; i < h; i++) {
if (visited[i][0] != 0) {
alive = true;
if (visited[i][0] < result)
result = visited[i][0];
}
if (visited[i][w - 1] != 0) {
alive = true;
if (visited[i][w - 1] < result)
result = visited[i][w - 1];
}
}
for (int j = 0; j < w; j++) {
if (visited[0][j] != 0) {
alive = true;
if (visited[0][j] < result)
result = visited[0][j];
}
if (visited[h - 1][j] != 0) {
alive = true;
if (visited[h - 1][j] < result)
result = visited[h - 1][j];
}
}
if (alive)
cout << result << '\n';
else
cout << "IMPOSSIBLE" << '\n';
}
int main() {
cin >> h >> w;
for (int i = 0; i < h; i++) {
string val;
cin >> val;
for (int j = 0; j < val.size(); j++)
arr[i][j] = val[j];
}
bfs();
}
상근이는 벽을 통과할 수 없고, 불이 옮겨진 칸 또는 이제 불이 붙으려는 칸으로 이동할 수 없다. 상근이가 있는 칸에 불이 옮겨옴과 동시에 다른 칸으로 이동할 수 있다.
이라고 하기 때문에 불을 먼저 움직여주면 됩니다.
알고리즘은
1. 불먼저 전파
2. 상근좌 이동
1, 2번을 상근좌가 이동가능한 칸이 있을 때 까지 반복
3. 결과 값 도출
순입니다.
정답코드입니다.
#include <iostream>
#include <queue>
#include <cstring>
#include <string>
using namespace std;
int t = 0, h = 0, w = 0;
int visited[1000][1000] = { 0 };
char arr[1000][1000];
queue <int> fire[2];
queue <int> people[2];
int x_ar[4] = { -1,1,0,0 };
int y_ar[4] = { 0,0,1,-1 };
void bfs() {
//초기값 입력
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++)
if (arr[i][j] == '*')
fire[0].push(i), fire[1].push(j);
else if(arr[i][j] == '@')
people[0].push(i), people[1].push(j), visited[i][j] = 1;
while (!people[0].empty()) { //상근이가 이동할 경로가 없을 때 까지 반복
//1. 불먼저 전파
int fire_cnt = fire[0].size();
while (fire_cnt--) {
int yy = fire[0].front();
int xx = fire[1].front();
fire[0].pop(), fire[1].pop();
for (int i = 0; i < 4; i++) {
int y = yy + y_ar[i];
int x = xx + x_ar[i];
if (y >= 0 && y < h && x >= 0 && x < w)
if (arr[y][x] == '.' || arr[y][x] == '@') {
arr[y][x] = '*';
fire[0].push(y), fire[1].push(x);
}
}
}
//2. 상근좌 이동
int people_cnt = people[0].size();
while (people_cnt--) {
int yy = people[0].front();
int xx = people[1].front();
people[0].pop(), people[1].pop();
for (int i = 0; i < 4; i++) {
int y = yy + y_ar[i];
int x = xx + x_ar[i];
if (y >= 0 && y < h && x >= 0 && x < w)
if (arr[y][x] == '.' && visited[y][x] == 0) {
visited[y][x] = visited[yy][xx] + 1;
people[0].push(y), people[1].push(x);
}
}
}
}
//3. 모서리의 visited값들을 확인하고 결과값을 도출
int result = 1000000;
bool alive = false;
for (int i = 0; i < h; i++) {
if (visited[i][0] != 0) {
alive = true;
if (visited[i][0] < result)
result = visited[i][0];
}
if (visited[i][w - 1] != 0) {
alive = true;
if (visited[i][w - 1] < result)
result = visited[i][w - 1];
}
}
for (int j = 0; j < w; j++) {
if (visited[0][j] != 0) {
alive = true;
if (visited[0][j] < result)
result = visited[0][j];
}
if (visited[h - 1][j] != 0) {
alive = true;
if (visited[h - 1][j] < result)
result = visited[h - 1][j];
}
}
if (alive)
cout << result << '\n';
else
cout << "IMPOSSIBLE" << '\n';
}
int main() {
cin >> t;
while (t--) {
memset(visited, 0, sizeof(visited));
while (!fire[0].empty())
fire[0].pop(), fire[1].pop();
cin >> w >> h;
for (int i = 0; i < h; i++) {
string val;
cin >> val;
for (int j = 0; j < val.size(); j++)
arr[i][j] = val[j];
}
bfs();
}
}
해당 문제는 n 배열과 m 배열을 내림차순으로 정렬하고 순서대로 큰 짐을 먼저 옮겨주면 되는 문제였습니다.
못 옮기는 기준은 가장 센 크레인 (arr_n[0])이 가장 무거운 짐(arr_m[0]) 보다 작을 때 입니다.
그리고 일반 배열에 O(n*m)로 구현하시면 시간초과입니다.
최악의 상황에 O(m*n*m) 이 되어 500,000,000로 5초가 걸리기 때문입니다.
정답코드입니다.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int arr_n[51] = { 0 };
vector <int> arr_m;
int n = 0, m = 0, result = 0;
bool cmp(int a, int b) {
if (a > b)return true;
return false;
}
int main() {
cin >> n;
for (int i = 0; i < n; i++)
cin >> arr_n[i];
cin >> m;
int num = 0;
for (int i = 0; i < m; i++) {
cin >> num;
arr_m.push_back(num);
}
sort(arr_n, arr_n + n, cmp);
sort(arr_m.begin(), arr_m.end(), cmp);
if (arr_n[0] < arr_m[0]) {
cout << -1 << endl;
return 0;
}
while (1) {
result++;
for (int i = 0; i < n; i++) {
for (int j = 0; j < arr_m.size(); j++) {
if (arr_n[i] >= arr_m[j]) {
arr_m.erase(arr_m.begin() + j);
break;
}
}
}
if (arr_m.size() == 0)
break;
}
cout << result << '\n';
}
소시지를 하나로 이어붙인 상태 즉, n = 1일때 m - 1번 잘라야 모두에게 같은 크기의 소시지를 줄 수 있다.
즉, 최악의 경우 m - 1 최소의 경우 0번이다.
그렇다면 소시지가 여러개가 있을 때 어떻게 해야할까?
최대공약수를 생각해보면 답이 나온다.
소시지를 일자로 두고 일정한 크기 만큼 자를 때 두 수의 (최대 공약수 - 1) 만큼 이미 잘려있을 것이다.
즉 식은 b - gcd(a,b) 이다.
#include <iostream>
using namespace std;
int n = 0, m = 0;
int GCD(int a, int b) {
if (a%b == 0)
return b;
return GCD(b, a%b);
}
int main() {
cin >> n >> m;
cout << m - GCD(n, m) << endl;
}
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int dp[1001][1001] = { 0 };
int result = 0, n = 0, m = 0;
string arr[1001];
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++)
cin >> arr[i];
for (int i = 0; i < n; i++) {
dp[i][0] = arr[i][0] - '0';
result = max(result, dp[i][0]);
}
for (int i = 0; i < m; i++) {
dp[0][i] = arr[0][i] - '0';
result = max(result, dp[0][i]);
}
for (int i = 1; i < n; i++)
for (int j = 1; j < m; j++) {
if (arr[i][j] == '1') {
dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - 1]);
dp[i][j] = min(dp[i][j - 1], dp[i][j]);
dp[i][j]++;
}
if (result < dp[i][j])
result = dp[i][j];
}
cout << result*result << '\n';
}
구현 능력을 보여주는데 적합하기 때문에 많은 코딩테스트에서 사용되는 단골 문제이기 때문에 꼭 연습하시길 추천 드립니다.
정말 다양한 방법이 있습니다. 우선 탐색을 통해서 값을 얻어야 하는데 dfs, bfs 모두 상관없습니다. (여기서는 dfs가 코드가 짧고 가독성이 좋습니다.)
알고리즘은
1. 탐색을 통해서 없애야 하는 인덱스들을 표시한다.
2. 없애야 하는 인덱스들을 없애고, 빈 칸들을 채워넣는다.
3. 없애야 하는 인덱스가 없을때 까지 반복한다.
주의 하실점은 연쇄로 터지는 것을 한번의 과정으로 본다는 것입니다.
저는 vector를 사용하였고, dfs 두가지를 이용해서 구현하였습니다.
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
using namespace std;
string val[12];
vector <char> arr[6];
int result = 0;
int x_ar[4] = { 1,-1,0,0 };
int y_ar[4] = { 0,0,1,-1 };
int visited[6][12] = { 0 };
void dfs2(char a, int yy, int xx,int cnt) {
int sum = cnt;
for (int i = 0; i < 4; i++) {
int y = yy + y_ar[i];
int x = xx + x_ar[i];
if (y >= 0 && y < 6 && x >= 0 && x < 12 && arr[y][x] == arr[yy][xx] && visited[y][x] == 0) {
sum++;
visited[y][x] = sum;
dfs2(a, y, x,sum );
}
}
}
void dfs(char a,int yy,int xx) {
arr[yy][xx] = '8';
visited[yy][xx] = -1;
for (int i = 0; i < 4; i++) {
int y = yy + y_ar[i];
int x = xx + x_ar[i];
if (y >= 0 && y < 6 && x >= 0 && x < 12 && arr[y][x] == a && visited[y][x] != -1) {
dfs(a, y, x);
}
}
}
bool solve() {
bool jud = false;
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 12; j++) {
if (arr[i][j] != '.' ) {
memset(visited, 0, sizeof(visited));
visited[i][j] = 1;
dfs2(arr[i][j], i, j, 1);
for (int u = 0; u < 6; u++)
for (int m = 0; m < 12; m++)
if (visited[u][m] >= 4) {
char word = arr[u][m];
dfs(word, u, m);
}
}
}
}
for (int i = 0; i < 6; i++)
for (int j = 0; j< arr[i].size(); j++)
if (arr[i][j] == '8') {
jud = true;
arr[i].erase(arr[i].begin() + j), j--;
}
for (int i = 0; i<6; i++)
if (arr[i].size() < 12) {
while (arr[i].size() != 12)
arr[i].push_back('.');
}
return jud;
}
int main() {
for (int i = 0; i < 12; i++) {
cin >> val[i];
}
for (int i = 0; i < 6; i++)
for (int j = 11; j >= 0; j--)
arr[i].push_back(val[j][i]);
while (1) {
bool jud = false;
jud = solve();
if (jud == false)
break;
result++;
}
cout << result << '\n';
}
벡터를 사용하기 위해 입력받은 문자열을 90도 회전해서 벡터에 넣었습니다.
dfs2를 호출해서 탐색하며 visited에 이동값들을 표시했습니다.
이후 dfs를 통해서 visited값이 4인 값과 연결되는 모든 arr값들을 '8'로 바꿔주었습니다.
그 이후 라운드별로 '8' 값들을 모두 지워주고 뒷부분을 '.' 로 채워주는 방식으로 구현했습니다.