마인크래프트 성공
1 초 (추가 시간 없음) | 1024 MB | 63220 | 16507 | 12271 | 23.731% |
문제
팀 레드시프트는 대회 준비를 하다가 지루해져서 샌드박스 게임인 ‘마인크래프트’를 켰다. 마인크래프트는 1 × 1 × 1(세로, 가로, 높이) 크기의 블록들로 이루어진 3차원 세계에서 자유롭게 땅을 파거나 집을 지을 수 있는 게임이다.
목재를 충분히 모은 lvalue는 집을 짓기로 하였다. 하지만 고르지 않은 땅에는 집을 지을 수 없기 때문에 땅의 높이를 모두 동일하게 만드는 ‘땅 고르기’ 작업을 해야 한다.
lvalue는 세로 N, 가로 M 크기의 집터를 골랐다. 집터 맨 왼쪽 위의 좌표는 (0, 0)이다. 우리의 목적은 이 집터 내의 땅의 높이를 일정하게 바꾸는 것이다. 우리는 다음과 같은 두 종류의 작업을 할 수 있다.
- 좌표 (i, j)의 가장 위에 있는 블록을 제거하여 인벤토리에 넣는다.
- 인벤토리에서 블록 하나를 꺼내어 좌표 (i, j)의 가장 위에 있는 블록 위에 놓는다.
1번 작업은 2초가 걸리며, 2번 작업은 1초가 걸린다. 밤에는 무서운 몬스터들이 나오기 때문에 최대한 빨리 땅 고르기 작업을 마쳐야 한다. ‘땅 고르기’ 작업에 걸리는 최소 시간과 그 경우 땅의 높이를 출력하시오.
단, 집터 아래에 동굴 등 빈 공간은 존재하지 않으며, 집터 바깥에서 블록을 가져올 수 없다. 또한, 작업을 시작할 때 인벤토리에는 B개의 블록이 들어 있다. 땅의 높이는 256블록을 초과할 수 없으며, 음수가 될 수 없다.
입력
첫째 줄에 N, M, B가 주어진다. (1 ≤ M, N ≤ 500, 0 ≤ B ≤ 6.4 × 107)
둘째 줄부터 N개의 줄에 각각 M개의 정수로 땅의 높이가 주어진다. (i + 2)번째 줄의 (j + 1)번째 수는 좌표 (i, j)에서의 땅의 높이를 나타낸다. 땅의 높이는 256보다 작거나 같은 자연수 또는 0이다.
출력
첫째 줄에 땅을 고르는 데 걸리는 시간과 땅의 높이를 출력하시오. 답이 여러 개 있다면 그중에서 땅의 높이가 가장 높은 것을 출력하시오.
예제 입력 1 복사
3 4 99
0 0 0 0
0 0 0 0
0 0 0 1
예제 출력 1 복사
2 0
맨 오른쪽 아래의 블록을 제거하면 모두 높이가 0으로 고른 상태가 된다. 따라서 블럭을 한 번 제거하는 시간 2초가 소요된다.
예제 입력 2 복사
3 4 1
64 64 64 64
64 64 64 64
64 64 64 63
예제 출력 2 복사
1 64
인벤토리에 블록이 하나 있기 때문에, 맨 오른쪽 아래에 블록을 하나 채우면 된다.
예제 입력 3 복사
3 4 0
64 64 64 64
64 64 64 64
64 64 64 63
예제 출력 3 복사
22 63
인벤토리가 비어 있기 때문에, 맨 오른쪽 아래를 제외한 모든 좌표에서 블록을 하나씩 제거해야 한다.
출처
University > 서강대학교 > 2019 Sogang Programming Contest > Champion B번
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
typedef struct TimeHight {
int time;
int height;
}MyTimeHight;
//qsort compare함수, 1순위로 time값을 비교하고, time값이 같을 경우 2순위로 height 비교. time과 height가 같은 경우만 0 반환
int compare_time(const void* a, const void* b) {
MyTimeHight* A = (MyTimeHight*)a;
MyTimeHight* B = (MyTimeHight*)b;
if (A->time > B->time)
return 1;
else if (A->time < B->time)
return -1;
else {
if (A->height > B->height)
return 1;
else if (A->height < B->height)
return -1;
else {
return 0;
}
}
}
//높이가 가장 높은 블럭의 높이 반환
int cal_highest(int** arr, int N, int M) {
int highest_num = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (arr[i][j] > highest_num)
highest_num = arr[i][j];
}
}
return highest_num;
}
//높이가 가장 낮은 블럭의 높이 반환
int cal_lowest(int** arr, int N, int M) {
int lowest_num = 256;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (arr[i][j] < lowest_num)
lowest_num = arr[i][j];
}
}
return lowest_num;
}
//집터를 goal 높이로 만드는데 걸리는 시간, 블럭이 부족하여 goal 높이로 만들 수 없을 경우 -1 리턴
int cal_time(int** arr, int N, int M, int B, int goal) {
int time = 0; //리턴값인 총 소요 시간
int need = 0; //쌓거나 빼야하는 블록 수
int total_needed = 0; //총 소요 블럭 수
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
need = goal - arr[i][j];
if (need < 0) { //블록을 빼야 하는 경우
time += -2 * need; //음수 처리
}
else if (need > 0) {
time += need;
}
total_needed += need;
}
}
if (total_needed <= B)
return time;
else
return -1; //블록이 부족한 경우
}
//최소 시간 중 가장 높은 높이를 가지는 경우의 (시간, 높이)값을 리턴하는 함수. 블록이 부족한 경우는 높이와 시간을 int_max로 할당하도록 하였다.
//또한, 걸리는 시간을 저장하기 위한 anss의 malloc 동적 할당을 실패할 경우, 높이와 시간을 -1로 할당하도록 하였다.
MyTimeHight calculate(int** arr, int N, int M, int B) {
int highest = cal_highest(arr, N, M);
int lowest = cal_lowest(arr, N, M);
int num_times = highest - lowest + 1;
MyTimeHight* anss = (MyTimeHight*)malloc(sizeof(MyTimeHight) * num_times);
MyTimeHight ans = { 0,0 };
int goal = lowest;
int result = 0;
if (anss != NULL) {
while (goal <= highest) {
result = cal_time(arr, N, M, B, goal);
if (result == -1) { //블록이 부족한 경우
anss[goal - lowest].time = 2147483647;
anss[goal - lowest].height = 2147483647;
}
else {
anss[goal - lowest].time = result;
anss[goal - lowest].height = goal;
}
goal++;
}
qsort(anss, num_times, sizeof(MyTimeHight), compare_time);
if (num_times > 1) {
if (anss[0].time == anss[1].time) {
int i = 0;
while (anss[i].time == anss[i + 1].time && i < num_times)
i++;
if (anss[i].time == anss[i + 1].time) {
ans.time = anss[i + 1].time;
ans.height = anss[i + 1].height;
}
ans.time = anss[i].time;
ans.height = anss[i].height;
}
else {
ans.time = anss[0].time;
ans.height = anss[0].height;
}
}
else {
ans.time = anss[0].time;
ans.height = anss[0].height;
}
free(anss);
return ans;
}
else {
ans.height = -1;
ans.time = -1;
return ans;
}
}
int main() {
int N, M, B;
scanf("%d %d %d", &N, &M, &B);
int** arr = (int**)malloc(sizeof(int*) * N);
if (arr == NULL) {
printf("malloc error\n");
return -1;
}
for (int i = 0; i < N; i++)
arr[i] = (int*)malloc(sizeof(int) * M);
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
scanf("%d", &arr[i][j]);
}
}
MyTimeHight ans = calculate(arr, N, M, B);
if(ans.time >= 0 && ans.height >= 0)
printf("%d %d", ans.time, ans.height);
else { //동적 할당 실패한 경우
printf("Malloc Allocation failed\n");
return -1;
}
for (int i = 0; i < N; i++)
free(arr[i]);
free(arr);
return 0;
}