/*
* Problem :: 17135 / 캐슬 디펜스
*
* Kind :: Simulation
*
* Insight
* - 궁수 3명에 max(M)=15 이면
* 15C3 = 455 정도 이고
* 적이 격자판 가득하면
* 다 내려오는데 O(N), 궁수가 공격할 적을 계산하는데
* 모든 적을 한번씩 검사한다면 O(NM)
* 외에 이러저러해도... O(N^2M) 정도일 듯 하다
* + 그래도 max(N,M)=15 이니
* 시간제한 때문에 최적화 걱정없이 구현에만 집중하면 되겠다
*
* - 일단 궁수 위치선정은 next_permutation 으로 할까 하다가
* 귀찮아서 3중 for 문으로 해결했다
* + 현재 격자판의 상태를 갱신하는 것으로 구현할까 싶었는데
* 곰곰이 생각해보니 그냥 적의 좌표만 갱신시켜주면 된다
* # 궁수가 공격할 적의 좌표를 계산하는 것은
* 결국 궁수와의 거리가 가장 가까운 적을 찾는 것이넫
* <algorithm> 의 min_element 함수를 이용하면 쉽게 구할 수 있을 것 같았다
* -> 공격할 적이 결정되면 이제 그 공격으로 적이 제거되어야 하는데
* Set 이 이와같은 과정에 적합한 자료구조라 생각했다
* (찾기도 쉽고, 제거도 쉬우니까)
* => 다만, Set 내부의 원소들은 const 로 건들 수가 없어서
* 적들이 아래로 한칸 이동하는 것은
* 새로운 임시의 Set 을 만들어서 해결했다
*
* Point
* - class 로 Comparator 에 parameter 를 넘겨주기
*/
//
// BOJ
// ver.C++
//
// Created by GGlifer
//
// Open Source
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
#define endl '\n'
// Set up : Global Variables
int N, M, D;
struct Point { int y, x; };
set<Point> E;
// Set up : Functions Declaration
bool operator < (const Point &u, const Point &v);
int tmp(int b1, int b2, int b3);
class Comp {
int pos;
public:
Comp(int b) { pos = b; }
bool operator()(const Point &p1, const Point &p2) const;
};
int main()
{
// Set up : I/O
ios::sync_with_stdio(false);
cin.tie(nullptr);
// Set up : Input
cin >> N >> M >> D;
for (int i=0; i<N; i++) {
for (int j=0; j<M; j++) {
int v; cin >> v;
if (v == 1) {
E.insert({i, j}); /* 적의 좌표 저장 */
}
}
}
// Process
int ans = -1;
for (int b1=0; b1<M; b1++) { /* 궁수 1의 x 좌표 */
for (int b2=b1+1; b2<M; b2++) { /* 궁수 2의 x 좌표 */
for (int b3=b2+1; b3<M; b3++) { /* 궁수 3의 x 좌표 */
ans = max(ans, tmp(b1, b2, b3));
}
}
}
// Control : Output
cout << ans << endl;
}
// Helper Functions
bool operator < (const Point &u, const Point &v)
/* Point 구조체 비교를 위한 연산자 오버로딩 (set<Point> 로 활용하기 위함) */
{
return make_pair(u.y, u.x) < make_pair(v.y, v.x);
}
bool Comp::operator()(const Point &p1, const Point &p2) const {
/* 궁수의 좌표 (N, pos) 로부터 가장 가까운 적의 좌표를
* min_element 함수를 사용하여 구하기 위한 Comparator */
int d1 = abs(p1.y-N) + abs(p1.x-pos);
int d2 = abs(p2.y-N) + abs(p2.x-pos);
return (d1 != d2) ? (d1 < d2) : (p1.x < p2.x);
}
int tmp(int b1, int b2, int b3)
/* 3명인 궁수들의 x 좌표인 b1, b2, b3 를 바탕으로 제거한 적의 최대 수를 반환 */
{
set<Point> R = E;
int cnt = 0; /* 제거한 적의 수 */
while (not(R.empty())) {
/* 궁수 1이 공격할 적의 좌표 */
Point t1 = *min_element(R.begin(), R.end(), Comp(b1));
int d1 = abs(t1.y-N) + abs(t1.x-b1); /* 궁수 1로부터 공격할 적의 좌표까지의 거리 */
/* 궁수 2가 공격할 적의 좌표 */
Point t2 = *min_element(R.begin(), R.end(), Comp(b2));
int d2 = abs(t2.y-N) + abs(t2.x-b2); /* 궁수 2로부터 공격할 적의 좌표까지의 거리 */
/* 궁수 3이 공격할 적의 좌표 */
Point t3 = *min_element(R.begin(), R.end(), Comp(b3));
int d3 = abs(t3.y-N) + abs(t3.x-b3); /* 궁수 3으로부터 공격할 적의 좌표까지의 거리 */
/* 각 궁수로부터 공격할 적의 좌표까지의 거리가 D 이하이고 공격할 적이 제거되지 않았다면
* 공격하여 적을 제거 */
if (d1 <= D && (R.find(t1) != R.end())) { R.erase(t1), cnt++; }
if (d2 <= D && (R.find(t2) != R.end())) { R.erase(t2), cnt++; }
if (d3 <= D && (R.find(t3) != R.end())) { R.erase(t3), cnt++; }
set<Point> T; /* 이동하고 남아있는 적의 좌표들 */
for (auto p : R) {
if (p.y+1 < N) {
T.insert({p.y+1, p.x});
}
}
R = T; /* 적들의 좌표 갱신 */
}
return cnt;
}