#include <bits/stdc++.h>
#define REP(i, n) for(int i=0; i < (int)(n); i++)
using namespace std;

typedef long long ll; // -9,223,372,036,854,775,808 から 9,223,372,036,854,775,807

template <class T> using vec = std::vector<T>;
template <class T> using vec2 = vec<vec<T>>;
template <class T> using vec3 = vec<vec<vec<T>>>;

// #define DEBUG

template <class T>
class Bitvector{
    private:
    T val;
    public:
    static const int MAX = 64;
    Bitvector(T v = 0){
        val = v;
    }

    static Bitvector<T> ones(int len){
        return Bitvector<T>((1 << len) - 1);
    }

    static Bitvector<T> onehot(int pos){
        return Bitvector<T>(1 << pos);
    }

    static Bitvector<T> full(){
        return Bitvector<T>(-1);
    }

    bool is_empty(){
        return val == 0;
    }

    bool is_any(){
        return !is_empty();
    }

    Bitvector<T> operator&(const Bitvector<T>& rhs) const{
        return Bitvector<T>(val & rhs.val);
    }

    Bitvector<T> operator|(const Bitvector<T>& rhs) const{
        return Bitvector<T>(val | rhs.val);
    }

    Bitvector<T> operator~() const{
        return Bitvector<T>(~val);
    }

    bool operator==(const Bitvector<T>& rhs) const{
        return val == rhs.val;
    }

    bool operator!=(const Bitvector<T>& rhs) const{
        return val != rhs.val;
    }


    Bitvector<T> c() const{
        return ~(*this);
    }

    Bitvector<T> operator-(const Bitvector<T>& rhs) const{
        return (*this) & ~rhs;
    }

    bool is_subset_of(const Bitvector<T>& rhs) const{
        // A ⊂ B は A-B = empty
        return (*this - rhs).is_empty();
    }

    bool operator<=(const Bitvector<T>& rhs) const{
        return is_subset_of(rhs);
    }

    bool operator>=(const Bitvector<T>& rhs) const{
        return rhs <= *this;
    }

    int operator[](int n) const{
        return (val >> n) & 1;
    }

    int next_bit(int n){
        for(int i=n+1; i < MAX; i++){
            if((*this)[i]){
                return i;
            }
        }
        return MAX;
    }

    int first_bit(){
        return next_bit(-1);
    }

    // もうないならfullをかえす
    Bitvector<T> get_next_subset(const Bitvector<T>& rhs){
        for(auto i=Bitvector<T>(rhs.val + 1); i <= full(); i++){
            if(i <= *this){
                return i;
            }
        }
        return full();
    }

    void go_next_subset(Bitvector<T>& rhs){
        auto n = get_next_subset(rhs);
        rhs = n;
    }

    int bits(){
        int res = 0;
        for(int i=0; i < MAX; i++){
            if((*this)[i]){
                res++;
            }
        }
        return res;
    }

    Bitvector<T> operator++(int n){
        return Bitvector<T>(val++);
    }

    Bitvector<T> on(int pos) const{
        return (*this) | onehot(pos);
    }

    
    Bitvector<T> off(int pos) const{
        return (*this) - onehot(pos);
    }


    string toString(int len){
        string s;
        for(int i=len - 1; i >= 0; i--){
            s += '0' + (*this)[i];
        }

        return s;
    }

    T raw(){
        return val;
    }
};
typedef Bitvector<long long> BV;

// for(int j=i.first_bit(); j < N; j=i.next_bit(j)){
//     for(int k=i.next_bit(j); k < N; k=i.next_bit(k)){
//         // iのたってるビットのペアをつくる
//     }
// }

// for(auto i=BV(); i <= BV::ones(N); i++){
//     // すべてのサブセットをなめる
// }


// for(auto i=BV(); i <= S; S.go_next_subset(i)){
//     // すべてのサブセットをなめる
// }

int H, W, K;
vec2<int> board;
vec2<ll> table; // ホワイトチョコをかぞえる
const ll INF = 100000;

ll countRect(int r1, int c1, int r2, int c2){
    assert(r1 <= r2 && c1 <= c2);
    // #ifdef DEBUG
    // printf("*START: countrect\n");
    // printf("%d %d %d %d\n", r1, c1, r2, c2);
    // printf("*END: countrect\n");
    // #endif
    return table[r2+1][c2+1] + table[r1][c1] - table[r2+1][c1] - table[r1][c2+1];
}

// cの右側できる
ll maxWhitesLeft(BV cut, int left, int c){
    if(!(c < W)){
        return maxWhitesLeft(cut, left, W-1);
    }
    if(c < 0){
        return 0;
    }
    
    vector<int> hCuts; // きるますの下のくぎり
    for(int i=0; i < H - 1; i++){
        if(cut[i] == 0){
            continue;
        }
        hCuts.push_back(i+1);
    }
    hCuts.push_back(H);

    ll res = 0;
    int top = 0;
    for(auto i: hCuts){
        res = max(res, countRect(top, left, i-1, c));
        top = i;
    }

    // #ifdef DEBUG
    // printf("*START: whitelet\n");
    // printf("left %d, c: %d, val: %d\n", left, c, res);
    // printf("*END: whitelet\n");
    // #endif

    return res;

}

ll cutVertical(BV cut){
    ll cuts = 0;
    int left = 0;

    while(true){
        ll b = left - 1;
        ll u = W;
        // f(-)は増加。減少なら不等式は>か>=にする。
        while(u - b > 1){
            ll piv = (u + b)/2;
            if(maxWhitesLeft(cut, left, piv) <= K){ // 必要なら不等号はとりかえる。とにかく左側がTRUEということにする(右がTRUEなら反転する)
                b = piv;
            }else{
                u = piv;
            }
        }
        // bはfがK未満(条件が真)の位置のうち一番右、uはfがK以上(条件が偽)の位置のうち一番左
        // #ifdef DEBUG
        // printf("*START: cut\n");
        // printf("Cut at b: %d, val at b is %d\n", b, maxWhitesLeft(cut, left, b));
        // printf("Cut at b: %d, val at b+1 is %d\n", b, maxWhitesLeft(cut, left, b+1));
        // printf("*END: cut\n");
        // #endif
        if(b < 0){
            // むり
            return INF;
        }
        left = b + 1;
        // cuts++;
        if(left >= W){
            //きりおわった
            break;
        }
        // きった
        cuts++;


    }

    return cuts;
}

int main(){
    cin >> H >> W >> K;
    board = vec2<int>(H, vec<int>(W, 0));
    for(int i=0; i < H; i++){
        for(int j=0; j < W; j++){
            while(true){
                char temp;
                cin >> temp;
                if(temp == '0'){
                    board[i][j] = 0;
                }else if(temp == '1'){
                    board[i][j] = 1;
                }else if(temp == ' ' || temp == '\n'){
                    continue;
                }else{
                    assert(0);
                }
                break;
            }
        }
    }

    // 累積和を準備
    // 一個ずらしてある
    table = vec2<ll>(H+1, vec<ll>(W+1, 0));
    
    for(int iR=1; iR <= H; iR++){
        // この行の累積和を用意
        vec<ll> acc(W + 1, 0);
        for(int iC=1; iC <= W; iC++){
            acc[iC] = acc[iC-1] + board[iR-1][iC-1];
        }
    
        // tableを更新
        for(int iC=1; iC <= W; iC++){
            table[iR][iC] = table[iR-1][iC] + acc[iC];
        }
    
    }

    // #ifdef DEBUG
    // printf("*START: ruiseki\n");
    // for(int i=0; i < table.size(); i++){
    //     for(int j=0; j < table[0].size(); j++){
    //         cout << table[i][j] << "\t";
    //     }
    //     cout << endl;
    // }
    // printf("*END: ruiseki\n");
    // #endif

    // すべてのきりかたをためす。すじは(H-1)本はいる
    ll res = INF;
    for(auto i=BV(); i <= BV::ones(H-1); i++){
        ll localRes = i.bits() + cutVertical(i);
        #ifdef DEBUG
        printf("*START: loclare\n");
        cout << i.toString(H-1) << "\t" << localRes << endl;
        printf("*END: loclare\n");
        #endif
        res = min(localRes, res);
    }

    cout << res << endl;
   
    
    return 0;
}

Measured memory_bytes: 384