/*
* Problem :: 17144 / 미세먼지 안녕!
*
* Kind :: Simulation
*
* Insight
* - 문제가 막 어렵지 않은데...
* 구현이 좀 까다롭다
* + 1. 미세먼지 확산
* 2. 미세먼지 청소
* 이 두 과정을 구현해야 한다
*
* - 미세먼지 확산
* + 모든 미세먼지의 확산이 동시에 일어난다
* # 옆칸의 미세먼지가 확산되었을 때, 현재칸의 미세먼지의 양이 늘어나면 안된다
* ^= 확산되는 미세먼지 양이 달라지기 때문에
* -> 현재 방안의 미세먼지 양을 저장하는 배열과
* 확산된 방안의 미세먼지 양을 저장하는 배열을 구분해주자
*
* - 미세먼지 청소
* + 북쪽의 순환영역과 남쪽의 순환영역을 나누어 구현해준다
* # 공기청정기안으로 들어오는 쪽의 값부터 한칸씩 이동해준다
* -> 다른 쪽 방향의 순환을 먼저 실행하면 값의 손실이 일어나게 된다
* 북쪽의 순환영역 기준, O : 공기청정기 윗부분
* <----
* | ^
* V |
* O--->
* 에서 아래쪽 방향이 아닌 왼쪽 방향부터 한칸씩 값을 이동시켜주면
* 아래쪽 방향과 왼쪽방향이 만나는 코너에 있는 값의 손실이 일어나게 된다
* -> 사실은, 먼저 이동시키는 방향과 그 방향에 닿아있는 방향의 코너에 있는 값의 손실이
* 필연적으로 일어나게 되는데 <= 따로 저장해두면 상관없겠지만
* 공기청정기에 있는 코너의 값은 어차피 정화되어 0 이 될테니 손실되어도 상관없다
* -> 공기청정기 안으로 들어오는 쪽의 방향부터 꼬리를 무는순서대로 값을 이동시켜주자
*
* Point
* - for 문 하드코딩...
* 더 좋은 방법이 생각나지 않아 ㅠㅠ
* + 배열로 순환순서를 넣어놀까 싶었는데
* 그건 그것대로 까다로워서...
*
* - 확산된 방안의 미세먼지 양을 구할 때
* 현재 칸의 미세먼지 양은 인접한 칸들의 영향을 받기 때문에
* '=' 가 아닌 '+=' 로 해주어야 한다!!!
*
* - 확산된 방안의 상태를 저장하는 배열을 만들 때,
* 값뿐만 아니라 공기청정기 위치도 초기화해주자
*/
//
// BOJ
// ver.C++
//
// Created by GGlifer
//
// Open Source
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
#define endl '\n'
// Set up : Global Variables
int R, C, T;
int board[50][50];
struct Point { int y, x; };
vector<Point> Cleaner;
int dy[4] = {+1, 0, 0, -1};
int dx[4] = {0, +1, -1, 0};
#define CLEANER (-1)
// Set up : Functions Declaration
bool isValid(int y, int x);
void spread();
void clean();
int main()
{
// Set up : I/O
ios::sync_with_stdio(false);
cin.tie(nullptr);
// Set up : Input
cin >> R >> C >> T;
for (int i=0; i<R; i++) {
for (int j=0; j<C; j++) {
cin >> board[i][j];
if (board[i][j] == -1) {
Cleaner.push_back({i, j});
}
}
}
// Process
while (T--) {
spread(); /* 미세먼지 확산 */
clean(); /* 미세먼지 청소 */
}
int ans = 0; /* T 초가 지난 후 미세먼지 총량 */
for (int i=0; i<R; i++) {
for (int j=0; j<C; j++) {
if (board[i][j] > 0) { /* 미세먼지가 있으면 */
ans += board[i][j]; /* 총량에 더해줌 */
}
}
}
// Control : Output
cout << ans << endl;
}
// Helper Functions
bool isValid(int y, int x)
/* 좌표 (y,x) 가 유효하면 true 를 반환, 그 외 false 를 반환 */
{
return y >= 0 && y < R && x >= 0 && x < C;
}
void spread()
/* 미세먼지 확산을 구현한 함수 */
{
/* int boaard[50][50] = 현재 방안의 상태 */
int update[50][50]; /* 확산된 방안의 상태 */
memset(update, 0, sizeof(update)); /* 미세먼지 양 초기화 */
Point n = Cleaner.front(), s = Cleaner.back();
update[n.y][n.x] = CLEANER; /* 공기청정기 위치 초기화 */
update[s.y][s.x] = CLEANER;
for (int i=0; i<R; i++) {
for (int j=0; j<C; j++) {
if (board[i][j] > 0) { /* 미세먼지가 있으면 */
int res = board[i][j]; /* 미세먼지 양 */
int amt = res / 5; /* 확산되는 양 */
int cnt = 0; /* 확산된 횟수 */
for (int k=0; k<4; k++) {
int ay = i + dy[k];
int ax = j + dx[k];
/* 인접한 칸이 유효하고, 공기청정기가 아니면 */
if (isValid(ay, ax) && board[ay][ax] != CLEANER) {
/* 확산 */
cnt++;
update[ay][ax] += amt;
}
}
/* 확산되고 남은 양 */
update[i][j] += res - cnt * amt;
}
}
}
/* 현재 방안의 상태를 확산된 방안의 상태로 갱신 */
memcpy(board, update, sizeof(board));
}
void clean()
/* 미세먼지 청소를 구현한 함수 */
{
/* 북쪽 순환 영역 */
Point n = Cleaner.front(); /* 공기청정기 윗부분 */
int ny = n.y, nx = n.x; /* 공기청정기 윗부분의 y 좌표, x 좌표 */
for (int i=ny-2; i>=0; i--) /* 북쪽 순환 영역 아래쪽 방향 <= 공기청정기로 들어오는 방향 */
board[i+1][0] = board[i][0];
for (int j=1; j<C; j++) /* 북쪽 순환 영역 왼쪽 방향 */
board[0][j-1] = board[0][j];
for (int i=1; i<=ny; i++) /* 북쪽 순환 영역 위쪽 방향 */
board[i-1][C-1] = board[i][C-1];
for (int j=C-2; j>=1; j--) /* 북쪽 순환 영역 오른쪽 방향 <= 공기청정기로부터 나가는 방향 */
board[ny][j+1] = board[ny][j];
board[ny][nx+1] = 0; /* 공기청정기 윗부분 오른쪽 칸은 정화되어 미세먼지 양이 0 이 됨 */
/* 남쪽 순환 영역 */
Point s = Cleaner.back(); /* 공기청정기 아랫부분 */
int sy = s.y, sx = s.x; /* 공기청정기 아랫부분의 y 좌표, x 좌표 */
for (int i=sy+2; i<R; i++) /* 남쪽 순환 영역 위쪽 방향 <= 공기청정기로 들어오는 방향 */
board[i-1][0] = board[i][0];
for (int j=1; j<C; j++) /* 남쪽 순환 영역 왼쪽 방향 */
board[R-1][j-1] = board[R-1][j];
for (int i=R-2; i>=sy; i--) /* 남쪽 순환 영역 아래쪽 방향 */
board[i+1][C-1] = board[i][C-1];
for (int j=C-2; j>=1; j--) /* 남쪽 순환 영역 오른쪽 방향 */
board[sy][j+1] = board[sy][j];
board[sy][sx+1] = 0; /* 공기청정기 아랫부분 오른쪽 칸은 정화되어 미세먼지 양이 0 이 됨 */
}