#include <bits/stdc++.h>
using namespace std;

#define pr(x) cout<< # x<< " = " << x <<endl

typedef long long  ll;
typedef long double ld;

const int N = 100005;
ll MOD = 1e9 + 7;

#define forn(i, n) for(int i = 0; i < (n); i++)

#define pb push_back
#define mp make_pair

#define max(a,b) ((a > b) ? a : b)
#define min(a,b) ((a < b) ? a : b)

vector<int> a2[2];
vector<int> a3[3];

vector<int> g[7];

void init(){
	int a[3];
	int b[3];
	for(int i = 0;i < 8;++i){
		for(int j = 0;j < 8;j++){
			int x = i;
			forn(pos,3){
				int d = x % 2;
				a[pos] = d;
				x = x / 2;
			}

			x = j;
			forn(pos,3){
				int d = x % 2;
				a[pos] = d;
				x = x / 2;
			}

			int sum0 = a[0] + a[1] + b[0] + b[1];
			int sum1 = a[1] + a[2] + b[1] + b[2];

			if(sum0 % 2 == 1){
				if(sum1 % 2 == 1){
					g[i].push_back(j);
				}
			}
		}

	}
}

int calc(int mask, const vector<int> &arr,int n){
	int ans = 0;
	for(int i = 0;i < n;++i){
		int d = mask % 2;
		mask /= 2;

		if(d != arr[i]){
			ans++;
		}
	}
	return ans;
}
void solve1(const vector<int> & a,int n){
		char c;
		int ans = 0;
		for(int i = 0;i < n;++i){
			int c = a[i];

			if(c == 0){
				ans++;
			}
		}
		cout<<ans<<endl;
}

void solve2(int m){

	ll dp [4][m];

	vector<int> g2[4];

	g2[0].push_back(1);
	g2[0].push_back(2);

	g2[1].push_back(3);

	g2[2].push_back(3);

	g2[3].push_back(1);
	g2[3].push_back(2);
	for(int i = 0;i < 4;++i){
		dp[i][0] = calc(i,{a2[0][0],a2[1][0]},2);
	}

	for(int i = 1;i < m;++i){
		for(int mask = 0;mask < 4;mask++){
			dp[mask][i] = calc(mask, {a2[0][i],a2[1][i]},2);

			int mn = 1e9;

			for(int v : g2[mask]){
				mn = min(mn,dp[v][i - 1]);
			}
			dp[mask][i] += mn;
		}
	}

	int mn = 1e9;

	for(int i = 0;i < 4;++i){
		mn = min(mn,dp[i][m - 1]);
	}

	cout<<mn<<endl;

}

void solve3(int m){
	ll dp [7][m];

	for(int i = 0;i < 8;++i){
		dp[i][0] = calc(i,{a3[0][0],a3[1][0],a3[2][0]},3);

	}

	for(int i = 1;i < m;++i){
		for(int mask = 0;mask < 8;mask++){
			dp[mask][i] = calc(mask, {a3[0][i],a3[1][i],a3[2][i]},3);

			int mn = 1e9;

			for(int v : g[mask]){
				mn = min(mn,dp[v][i - 1]);
			}
			dp[mask][i] += mn;
		}
	}

	int mn = 1e9;

	for(int i = 0;i < 8;++i){
		mn = min(mn,dp[i][m - 1]);
	}

	cout<<mn<<endl;
}

void solve(){
	int n,m;
	init();
	cin>>n>>m;

	if(n  > 4 || m > 4){
		cout<<-1<<endl;
		return;
	}

	char c;
	if(n == 1){
		vector<int> a(m);

		char c = 0;
		for(int i = 0;i < m;++i){
			cin>>c;

			if(c == '0'){
				a[i] = 0;

			}
			else{
				a[i] = 1;
			}
		}

		solve1(a, m);
		return;
	}

	if(m == 1){
		vector<int> a(n);

		char c = 0;
		for(int i = 0;i < n;++i){
			cin>>c;

			if(c == '0'){
				a[i] = 0;

			}
			else{
				a[i] = 1;
			}
		}

		solve1(a, n);
		return;
	}

	if(n == 2){
		char c;
		for(int i = 0;i < m;++i){
			cin>>c;
			if(c == '0'){
				a2[0].push_back(0);
			}
			else{
				a2[0].push_back(1);
			}
		}
		for(int i = 0;i < m;++i){
			cin>>c;
			if(c == '0'){
				a2[1].push_back(0);
			}
			else{
				a2[1].push_back(1);
			}
		}

		solve2(m);

		return;

	}

	if(m == 2){
		char c;

		for(int i = 0;i < n;++i){
			cin>>c;

			if(c == '0'){
				a2[0].push_back(0);
			}
			else{
				a2[0].push_back(1);
			}

			cin>>c;

			if(c == '0'){
				a2[1].push_back(0);
			}
			else{
				a2[1].push_back(1);
			}

		}

		solve2(n);

		return;

	}

	if(n == 3){
		char c;

		for(int i = 0;i < m;++i){
			cin>>c;
			if(c == '0'){
				a3[0].push_back(0);
			}
			else{
				a3[0].push_back(1);

			}
		}
		for(int i = 0;i < m;++i){
			cin>>c;
			if(c == '0'){
				a3[1].push_back(0);
			}
			else{
				a3[1].push_back(1);
			}
		}

		for(int i = 0;i < m;++i){
			cin>>c;
			if(c == '0'){
				a3[2].push_back(0);
			}
			else{
				a3[2].push_back(1);
			}
		}

		solve3(m);

		return;

	}

	if(m == 2){
		char c;

		for(int i = 0;i < n;++i){
			cin>>c;

			if(c == '0'){
				a3[0].push_back(0);
			}
			else{
				a3[0].push_back(1);
			}

			cin>>c;

			if(c == '0'){
				a3[1].push_back(0);
			}
			else{
				a3[1].push_back(1);
			}

			cin>>c;

			if(c == '0'){
				a3[2].push_back(0);
			}
			else{
				a3[2].push_back(1);
			}

		}

		solve3(n);

		return;

	}

}

int main(){
    //freopen("a.in", "r", stdin);
	//freopen("a.out", "w", stdout);
	ios_base::sync_with_stdio(0);
	cin.tie();
	cout.tie();

    int t = 1;

    while(t--){
        solve();
   }
}


#include <bits/stdc++.h>
using namespace std;

#define pr(x) cout<< # x<< " = " << x <<endl

typedef long long  ll;
typedef long double ld;

const int N = 100005;
ll MOD = 1e9 + 7;

#define forn(i, n) for(int i = 0; i < (n); i++)

#define pb push_back
#define mp make_pair

#define max(a,b) ((a > b) ? a : b)
#define min(a,b) ((a < b) ? a : b)

vector<int> a2[2];
vector<int> a3[3];

vector<int> g[7];

void init(){
	int a[3];
	int b[3];
	for(int i = 0;i < 7;++i){
		for(int j = 0;j < 7;j++){
			int x = i;
			forn(pos,3){
				int d = x % 2;
				a[pos] = d;
				x = x / 2;
			}

			x = j;
			forn(pos,3){
				int d = x % 2;
				a[pos] = d;
				x = x / 2;
			}

			int sum0 = a[0] + a[1] + b[0] + b[1];
			int sum1 = a[1] + a[2] + b[1] + b[2];

			if(sum0 % 2 == 1){
				if(sum1 % 2 == 1){
					g[i].push_back(j);
				}
			}
		}

	}
}

int calc(int mask, const vector<int> &arr,int n){
	int ans = 0;
	for(int i = 0;i < n;++i){
		int d = mask % 2;
		mask /= 2;

		if(d != arr[i]){
			ans++;
		}
	}
	return ans;
}
void solve1(const vector<int> & a,int n){
		char c;
		int ans = 0;
		for(int i = 0;i < n;++i){
			int c = a[i];

			if(c == 0){
				ans++;
			}
		}
		cout<<ans<<endl;
}

void solve2(int m){

	ll dp [4][m];

	vector<int> g2[4];

	g2[0].push_back(1);
	g2[0].push_back(2);

	g2[1].push_back(3);

	g2[2].push_back(3);

	g2[3].push_back(1);
	g2[3].push_back(2);
	for(int i = 0;i < 4;++i){
		dp[i][0] = calc(i,{a2[0][0],a2[1][0]},2);
	}

	for(int i = 1;i < m;++i){
		for(int mask = 0;mask < 4;mask++){
			dp[mask][i] = calc(mask, {a2[0][i],a2[1][i]},2);

			int mn = 1e9;

			for(int v : g2[mask]){
				mn = min(mn,dp[mask][i - 1]);
			}
			dp[mask][i] += mn;
		}
	}

	int mn = 1e9;

	for(int i = 0;i < 4;++i){
		mn = min(mn,dp[i][m - 1]);
	}

	cout<<mn<<endl;

}

void solve3(int m){
	ll dp [4][m];

	for(int i = 0;i < 7;++i){
		dp[i][0] = calc(i,{a3[0][0],a3[1][0],a3[2][0]},3);
	}

	for(int i = 1;i < m;++i){
		for(int mask = 0;mask < 7;mask++){
			dp[mask][i] = calc(mask, {a3[0][i],a3[1][i],a3[2][i]},3);

			int mn = 1e9;

			for(int v : g[mask]){
				mn = min(mn,dp[mask][i - 1]);
			}
			dp[mask][i] += mn;
		}
	}

	int mn = 1e9;

	for(int i = 0;i < 7;++i){
		mn = min(mn,dp[i][m - 1]);
	}

	cout<<mn<<endl;
}

void solve(){
	int n,m;
	init();
	cin>>n>>m;

	if(n  > 4 || m > 4){
		cout<<-1<<endl;
		return;
	}

	char c;
	if(n == 1){
		vector<int> a(m);

		char c = 0;
		for(int i = 0;i < m;++i){
			cin>>c;

			if(c == '0'){
				a[i] = 0;

			}
			else{
				a[i] = 1;
			}
		}

		solve1(a, m);
		return;
	}

	if(m == 1){
		vector<int> a(n);

		char c = 0;
		for(int i = 0;i < n;++i){
			cin>>c;

			if(c == '0'){
				a[i] = 0;

			}
			else{
				a[i] = 1;
			}
		}

		solve1(a, n);
		return;
	}

	if(n == 2){
		char c;
		for(int i = 0;i < m;++i){
			cin>>c;
			if(c == '0'){
				a2[0].push_back(0);
			}
			else{
				a2[0].push_back(1);
			}
		}
		for(int i = 0;i < m;++i){
			cin>>c;
			if(c == '0'){
				a2[1].push_back(0);
			}
			else{
				a2[1].push_back(1);
			}
		}

		solve2(m);

		return;

	}

	if(m == 2){
		char c;

		for(int i = 0;i < n;++i){
			cin>>c;

			if(c == '0'){
				a2[0].push_back(0);
			}
			else{
				a2[0].push_back(1);
			}

			cin>>c;

			if(c == '0'){
				a2[1].push_back(0);
			}
			else{
				a2[1].push_back(1);
			}

		}

		solve2(n);

		return;

	}

	if(n == 3){
		char c;
		for(int i = 0;i < m;++i){
			cin>>c;
			if(c == '0'){
				a3[0].push_back(0);
			}
			else{
				a3[0].push_back(1);

			}
		}
		for(int i = 0;i < m;++i){
			cin>>c;
			if(c == '0'){
				a3[1].push_back(0);
			}
			else{
				a3[1].push_back(1);
			}
		}

		for(int i = 0;i < m;++i){
			cin>>c;
			if(c == '0'){
				a3[2].push_back(0);
			}
			else{
				a3[2].push_back(1);
			}
		}

		solve3(m);

		return;

	}

	if(m == 2){
		char c;

		for(int i = 0;i < n;++i){
			cin>>c;

			if(c == '0'){
				a3[0].push_back(0);
			}
			else{
				a3[0].push_back(1);
			}

			cin>>c;

			if(c == '0'){
				a3[1].push_back(0);
			}
			else{
				a3[1].push_back(1);
			}

			cin>>c;

			if(c == '0'){
				a3[2].push_back(0);
			}
			else{
				a3[2].push_back(1);
			}

		}

		solve3(n);

		return;

	}

}

int main(){
    //freopen("a.in", "r", stdin);
	//freopen("a.out", "w", stdout);
	ios_base::sync_with_stdio(0);
	cin.tie();
	cout.tie();

    int t = 1;

    while(t--){
        solve();
   }
}


#include <bits/stdc++.h>
using namespace std;

#define pr(x) cout<< # x<< " = " << x <<endl

typedef long long  ll;
typedef long double ld;

const int N = 100005;
ll MOD = 1e9 + 7;

#define forn(i, n) for(int i = 0; i < (n); i++)

#define pb push_back
#define mp make_pair

#define max(a,b) ((a > b) ? a : b)
#define min(a,b) ((a < b) ? a : b)

vector<int> a2[2];
vector<int> a3[3];

vector<int> g[7];

void init(){
	int a[3];
	int b[3];
	for(int i = 0;i < 7;++i){
		for(int j = 0;j < 7;j++){
			int x = i;
			forn(pos,3){
				int d = x % 2;
				a[pos] = d;
				x = x / 2;
			}

			x = j;
			forn(pos,3){
				int d = x % 2;
				a[pos] = d;
				x = x / 2;
			}

			int sum0 = a[0] + a[1] + b[0] + b[1];
			int sum1 = a[1] + a[2] + b[1] + b[2];

			if(sum0 % 2 == 1){
				if(sum1 % 2 == 1){
					g[i].push_back(j);
				}
			}
		}

	}
}

int calc(int mask, const vector<int> &arr,int n){
	int ans = 0;
	for(int i = 0;i < n;++i){
		int d = mask % 2;
		mask /= 2;

		if(d != arr[i]){
			ans++;
		}
	}
	return ans;
}
void solve1(const vector<int> & a,int n){
		char c;
		int ans = 0;
		for(int i = 0;i < n;++i){
			int c = a[i];

			if(c == 0){
				ans++;
			}
		}
		cout<<ans<<endl;
}

void solve2(int m){

	ll dp [4][m];

	vector<int> g2[4];

	g2[0].push_back(1);
	g2[0].push_back(2);

	g2[1].push_back(3);

	g2[2].push_back(3);

	g2[3].push_back(1);
	g2[3].push_back(2);
	for(int i = 0;i < 4;++i){
		dp[i][0] = calc(i,{a2[0][0],a2[1][0]},2);
	}

	for(int i = 1;i < m;++i){
		for(int mask = 0;mask < 4;mask++){
			dp[mask][i] = calc(mask, {a2[0][i],a2[1][i]},2);

			int mn = 1e9;

			for(int v : g2[mask]){
				mn = min(mn,dp[mask][i - 1]);
			}
			dp[mask][i] += mn;
		}
	}

	int mn = 1e9;

	for(int i = 0;i < 4;++i){
		mn = min(mn,dp[i][m - 1]);
	}

	cout<<mn<<endl;

}

void solve3(int m){
	ll dp [4][m];

	for(int i = 0;i < 7;++i){
		dp[i][0] = calc(i,{a3[0][0],a3[1][0],a3[2][0]},3);
	}

	for(int i = 1;i < m;++i){
		for(int mask = 0;mask < 7;mask++){
			dp[mask][i] = calc(mask, {a3[0][i],a3[1][i],a3[2][i]},3);

			int mn = 1e9;

			for(int v : g[mask]){
				mn = min(mn,dp[mask][i - 1]);
			}
			dp[mask][i] += mn;
		}
	}

	int mn = 1e9;

	for(int i = 0;i < 7;++i){
		mn = min(mn,dp[i][m - 1]);
	}

	cout<<mn<<endl;
}

void solve(){
	int n,m;
	init();
	cin>>n>>m;

	if(n  > 4 || m > 4){
		cout<<-1<<endl;
		return;
	}

	char c;
	if(n == 1){
		vector<int> a(m);

		char c = 0;
		for(int i = 0;i < m;++i){
			cin>>c;

			if(c == '0'){
				a[i] = 0;

			}
			else{
				a[i] = 1;
			}
		}

		solve1(a, m);
		return;
	}

	if(m == 1){
		vector<int> a(n);

		char c = 0;
		for(int i = 0;i < n;++i){
			cin>>c;

			if(c == '0'){
				a[i] = 0;

			}
			else{
				a[i] = 1;
			}
		}

		solve1(a, n);
		return;
	}

	if(n == 2){
		char c;
		for(int i = 0;i < m;++i){
			cin>>c;
			if(c == '0'){
				a2[0].push_back(0);
			}
			else{
				a2[0].push_back(1);
			}
		}
		for(int i = 0;i < m;++i){
			cin>>c;
			if(c == '0'){
				a2[1].push_back(0);
			}
			else{
				a2[1].push_back(1);
			}
		}

		solve2(m);

		return;

	}

	if(m == 2){
		char c;

		for(int i = 0;i < n;++i){
			cin>>c;

			if(c == '0'){
				a2[0].push_back(0);
			}
			else{
				a2[0].push_back(1);
			}

			cin>>c;

			if(c == '0'){
				a2[1].push_back(0);
			}
			else{
				a2[1].push_back(1);
			}

		}

		solve2(n);

		return;

	}

	if(n == 3){
		char c;
		for(int i = 0;i < m;++i){
			cin>>c;
			if(c == '0'){
				a3[0].push_back(0);
			}
			else{
				a3[0].push_back(1);
			}
		}
		for(int i = 0;i < m;++i){
			cin>>c;
			if(c == '0'){
				a3[1].push_back(0);
			}
			else{
				a3[1].push_back(1);
			}
		}

		for(int i = 0;i < m;++i){
			cin>>c;
			if(c == '0'){
				a3[2].push_back(0);
			}
			else{
				a3[2].push_back(1);
			}
		}

		solve3(m);

		return;

	}

	if(m == 2){
		char c;

		for(int i = 0;i < n;++i){
			cin>>c;

			if(c == '0'){
				a3[0].push_back(0);
			}
			else{
				a3[0].push_back(1);
			}

			cin>>c;

			if(c == '0'){
				a3[1].push_back(0);
			}
			else{
				a3[1].push_back(1);
			}

			cin>>c;

			if(c == '0'){
				a3[2].push_back(0);
			}
			else{
				a3[2].push_back(1);
			}

		}

		solve3(n);

		return;

	}

}

int main(){
    //freopen("a.in", "r", stdin);
	//freopen("a.out", "w", stdout);
	ios_base::sync_with_stdio(0);
	cin.tie();
	cout.tie();

    int t = 1;

    while(t--){
        solve();
   }
}


#include <bits/stdc++.h>
using namespace std;
#define sc(x) scanf("%d", &(x))
#define sclld(x) scanf("%lld", &(x))
#define sz(x) int((x).size())
#define all(x) (x).begin(), (x).end()
#define MT make_tuple
#define MP make_pair
#define lastOne(x) (31 - __builtin_clz(x))
#define debug(x) cout<<(#x)<<": \""<<x<<"\""<<endl
#define debugVec(vec) cout<<(#vec)<<": "; for (auto& i: vec) cout<<i<<" "; cout<<endl

typedef long long ll;
typedef pair<int, int> ii;
const double PI = 2*acos(0);
const double EPS =  1e-9;
const int oo = 1e9;
const ll MOD = 1e9+7;

const int N = 4;
int n, m;
char grid[N][N], temp[N][N];
int solve(int idx, bool val)
{
    if (idx == n*m)
    {
        bool valid = 1;
        for (int r1 = 0; r1+2 <= n && valid; r1++)
        {
            for (int c1 = 0; c1+2 <= m && valid; c1++)
            {
                int cnt = 0;
                for (int i = r1; i < r1+2; i++)
                    for (int j = c1; j < c1+2; j++)
                        cnt += (temp[i][j] == '1');
                if (~cnt&1)
                    valid = 0;
            }
        }
        if (!valid)
            return oo;
        int changes = 0;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                if (grid[i][j] != temp[i][j])
                    changes++;
        return changes;
    }
    int i = idx/m, j = idx%m;
    temp[i][j] = val+'0';
    return min(solve(idx+1, 0), solve(idx+1, 1));
}

int main()
{
    scanf("%d%d", &n, &m);
    if (n >= 4 && m >= 4)
        return puts("-1");
    for (int i = 0; i < n; i++)
    {
        scanf("%s", grid[i]);
    }
    printf("%d\n", min(solve(0, 0), solve(0, 1)));

    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define sc(x) scanf("%d", &(x))
#define sclld(x) scanf("%lld", &(x))
#define sz(x) int((x).size())
#define all(x) (x).begin(), (x).end()
#define MT make_tuple
#define MP make_pair
#define lastOne(x) (31 - __builtin_clz(x))
#define debug(x) cout<<(#x)<<": \""<<x<<"\""<<endl
#define debugVec(vec) cout<<(#vec)<<": "; for (auto& i: vec) cout<<i<<" "; cout<<endl

typedef long long ll;
typedef pair<int, int> ii;
const double PI = 2*acos(0);
const double EPS =  1e-9;
const int oo = 1e9;
const ll MOD = 1e9+7;

int n, m;
const int N = 1e6+5;
int arr[N];
bool grid[4][N];
int dp[N][8];
int ok[8][8];

bool isValid(int mask1, int mask2)
{
    int &ret = ok[mask1][mask2];
    if (~ret)
        return ret;
    int cnt = __builtin_popcount(mask1&3) + __builtin_popcount(mask2&3);
    if (~cnt&1)
        return ret = false;
    if (n == 3)
    {
        cnt = __builtin_popcount(mask1&6) + __builtin_popcount(mask2&6);
        if (~cnt&1)
            return ret = false;
    }
    return ret = true;
}

int solve(int idx, int mask)
{
    if (idx == m-1)
        return 0;
    int & ret = dp[idx][mask];
    if (~ret)
        return ret;
    ret = oo;
    for (int m2 = 0; m2 < (1<<n); m2++)
    {
        if (isValid(mask, m2))
            ret = min(ret, solve(idx+1, m2)+__builtin_popcount(m2 ^ arr[idx+1]));
    }
    return ret;
}

int main()
{
    scanf("%d%d", &n, &m);

    if (n >= 4)
        puts("-1");
    else if (n == 1)
        puts("0");
    else
    {
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                char x;
                scanf(" %c", &x);
                grid[i][j] = (x == '1');
            }
        }
        for (int c = 0; c < m; c++)
        {
            arr[c] = 0;
            for (int r = 0; r < n; r++)
            {
                if (grid[r][c])
                    arr[c] |= (1<<r);
            }
        }
        memset(dp, -1, sizeof(dp));
        memset(ok, -1, sizeof(ok));

        int ans = oo;
        for (int i = 0; i < (1<<n); i++)
            ans = min(ans, solve(0, i)+__builtin_popcount(i ^ arr[0]));
        printf("%d\n", ans);
    }

    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define sc(x) scanf("%d", &(x))
#define sclld(x) scanf("%lld", &(x))
#define sz(x) int((x).size())
#define all(x) (x).begin(), (x).end()
#define MT make_tuple
#define MP make_pair
#define lastOne(x) (31 - __builtin_clz(x))
#define debug(x) cout<<(#x)<<": \""<<x<<"\""<<endl
#define debugVec(vec) cout<<(#vec)<<": "; for (auto& i: vec) cout<<i<<" "; cout<<endl

typedef long long ll;
typedef pair<int, int> ii;
const double PI = 2*acos(0);
const double EPS =  1e-9;
const int oo = 1e9;
const ll MOD = 1e9+7;

int n, m;
vector<vector<bool>> grid;
int solve(vector<vector<bool>> grid)
{
    int n = sz(grid), m = sz(grid[0]);
    int ans = 0;
    if (n == 2)
    {
        for (int c = 0; c+2 <= m; c++)
        {
            int cnt = 0;
            for (int i = 0; i < 2; i++)
                for (int j = c; j < c+2; j++)
                    cnt += grid[i][j];
            if (~cnt&1)
                ans++, grid[0][c+1].flip();
        }
    }
    else if (n == 3)
    {
        for (int c = 0; c+2 <= m; c++)
        {
            int cnt1 = 0, cnt2 = 0;
            for (int i = 0; i < 2; i++)
                for (int j = c; j < c+2; j++)
                    cnt1 += grid[i][j];
            for (int i = 1; i < 3; i++)
                for (int j = c; j < c+2; j++)
                    cnt2 += grid[i][j];
            if ((~cnt1&1) && (~cnt2&1))
                ans++, grid[1][c+1].flip();
            else if (~cnt1&1)
                ans++, grid[0][c+1].flip();
            else if (~cnt2&1)
                ans++, grid[2][c+1].flip();

        }

    }
    return ans;
}

int main()
{
    scanf("%d%d", &n, &m);
    bool swapped = 0;
    if (n > m)
    {
        swapped = 1;
        swap(n, m);
    }
    grid.assign(n, vector<bool>(m, 0));
    if (swapped)
    {
        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++)
            {
                char x;
                scanf(" %c", &x);
                grid[j][i] = (x == '1');
            }
    }
    else
    {
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
            {
                char x;
                scanf(" %c", &x);
                grid[i][j] = (x == '1');
            }
    }
    int x = min(n, m);
    if (x >= 4)
        puts("-1");
    else if (x == 1)
        puts("0");
    else if (x == 2)
    {
        int ans = solve(grid);
        grid[0][0].flip();
        ans = min(ans, solve(grid)+1);
        printf("%d\n", ans);
    }
    else if (x == 3)
    {
        int ans = solve(grid);
        grid[0][0].flip();
        ans = min(ans, solve(grid)+1);
        grid[0][0].flip();
        grid[1][0].flip();
        ans = min(ans, solve(grid)+1);
        grid[1][0].flip();
        grid[2][0].flip();
        ans = min(ans, solve(grid)+1);
        printf("%d\n", ans);
    }

    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define sc(x) scanf("%d", &(x))
#define sclld(x) scanf("%lld", &(x))
#define sz(x) int((x).size())
#define all(x) (x).begin(), (x).end()
#define MT make_tuple
#define MP make_pair
#define lastOne(x) (31 - __builtin_clz(x))
#define debug(x) cout<<(#x)<<": \""<<x<<"\""<<endl
#define debugVec(vec) cout<<(#vec)<<": "; for (auto& i: vec) cout<<i<<" "; cout<<endl

typedef long long ll;
typedef pair<int, int> ii;
const double PI = 2*acos(0);
const double EPS =  1e-9;
const int oo = 1e9;
const ll MOD = 1e9+7;

int n, m;
vector<string> grid, temp;
int solve(int idx, bool val)
{
    if (idx == n*m)
    {
        bool valid = 1;
        for (int r1 = 0; r1+2 <= n && valid; r1++)
        {
            for (int c1 = 0; c1+2 <= m && valid; c1++)
            {
                int cnt = 0;
                for (int i = r1; i < r1+2; i++)
                    for (int j = c1; j < c1+2; j++)
                        cnt += (temp[i][j] == '1');
                if (~cnt&1)
                    valid = 0;
            }
        }
        if (!valid)
            return oo;
        int changes = 0;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                if (grid[i][j] != temp[i][j])
                    changes++;
        return changes;
    }
    int i = idx/m, j = idx%m;
    temp[i][j] = val+'0';
    return min(solve(idx+1, 0), solve(idx+1, 1));
}

int main()
{
    scanf("%d%d", &n, &m);

    grid.assign(n, string(m, '0'));
    temp = grid;
    for (int i = 0; i < n; i++)
    {
        cin>>grid[i];
    }
    if (n >= 4 && m >= 4)
        puts("-1");
    else
        printf("%d\n", min(solve(0, 0), solve(0, 1)));

    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define sc(x) scanf("%d", &(x))
#define sclld(x) scanf("%lld", &(x))
#define sz(x) int((x).size())
#define all(x) (x).begin(), (x).end()
#define MT make_tuple
#define MP make_pair
#define lastOne(x) (31 - __builtin_clz(x))
#define debug(x) cout<<(#x)<<": \""<<x<<"\""<<endl
#define debugVec(vec) cout<<(#vec)<<": "; for (auto& i: vec) cout<<i<<" "; cout<<endl

typedef long long ll;
typedef pair<int, int> ii;
const double PI = 2*acos(0);
const double EPS =  1e-9;
const int oo = 1e9;
const ll MOD = 1e9+7;

const int N = 5;
int n, m;
char grid[N][N], temp[N][N];
int solve(int idx, bool val)
{
    if (idx == n*m)
    {
        bool valid = 1;
        for (int r1 = 0; r1+2 <= n && valid; r1++)
        {
            for (int c1 = 0; c1+2 <= m && valid; c1++)
            {
                int cnt = 0;
                for (int i = r1; i < r1+2; i++)
                    for (int j = c1; j < c1+2; j++)
                        cnt += (temp[i][j] == '1');
                if (~cnt&1)
                    valid = 0;
            }
        }
        if (!valid)
            return oo;
        int changes = 0;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                if (grid[i][j] != temp[i][j])
                    changes++;
        return changes;
    }
    int i = idx/m, j = idx%m;
    temp[i][j] = val+'0';
    return min(solve(idx+1, 0), solve(idx+1, 1));
}

int main()
{
    scanf("%d%d", &n, &m);
    if (n >= 4 && m >= 4)
        return puts("-1");
    for (int i = 0; i < n; i++)
    {
        scanf("%s", grid[i]);
    }
    printf("%d\n", min(solve(0, 0), solve(0, 1)));

    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define sc(x) scanf("%d", &(x))
#define sclld(x) scanf("%lld", &(x))
#define sz(x) int((x).size())
#define all(x) (x).begin(), (x).end()
#define MT make_tuple
#define MP make_pair
#define lastOne(x) (31 - __builtin_clz(x))
#define debug(x) cout<<(#x)<<": \""<<x<<"\""<<endl
#define debugVec(vec) cout<<(#vec)<<": "; for (auto& i: vec) cout<<i<<" "; cout<<endl

typedef long long ll;
typedef pair<int, int> ii;
const double PI = 2*acos(0);
const double EPS =  1e-9;
const int oo = 1e9;
const ll MOD = 1e9+7;

int n, m;
const int N = 1e6+5;
int arr[N];
bool grid[N][4];
int dp[N][8];
bool isValid(int mask1, int mask2)
{
    vector<string> grid2;
    if (n == 2)
    {
        grid2.push_back(bitset<2>(mask1).to_string());
        grid2.push_back(bitset<2>(mask2).to_string());
    }
    else if (n == 3)
    {
        grid2.push_back(bitset<3>(mask1).to_string());
        grid2.push_back(bitset<3>(mask2).to_string());
    }
    for (int c = 0; c < n-1; c++)
    {
        int cnt = 0;
        for (int i = 0; i < 2; i++)
            for (int j = c; j < c+2; j++)
                cnt += grid2[i][j] == '1';
        if (~cnt&1)
            return false;
    }
    return true;
}

int solve(int idx, int mask)
{
    if (idx == m-1)
        return 0;
    int & ret = dp[idx][mask];
    if (~ret)
        return ret;
    ret = oo;
    for (int m2 = 0; m2 < (1<<n); m2++)
    {
        if (isValid(mask, m2))
            ret = min(ret, solve(idx+1, m2)+__builtin_popcount(m2 ^ arr[idx+1]));
    }
    return ret;
}

int main()
{
    scanf("%d%d", &n, &m);
    if (n > m)
    {
        swap(n, m);
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                char x;
                scanf(" %c", &x);
                grid[j][i] = (x == '1');
            }
        }
    }
    else
    {
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                char x;
                scanf(" %c", &x);
                grid[i][j] = (x == '1');
            }
        }
    }
    int x = min(n, m);
    if (x >= 4)
        puts("-1");
    else if (x == 1)
        puts("0");
    else
    {
        memset(dp, -1, sizeof(dp));
        for (int c = 0; c < m; c++)
        {
            arr[c] = 0;
            for (int r = 0; r < n; r++)
            {
                if (grid[r][c])
                    arr[c] |= (1<<r);
            }
        }

        int ans = oo;
        for (int i = 0; i < (1<<n); i++)
            ans = min(ans, solve(0, i)+__builtin_popcount(i ^ arr[0]));
        printf("%d\n", ans);
    }

    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define sc(x) scanf("%d", &(x))
#define sclld(x) scanf("%lld", &(x))
#define sz(x) int((x).size())
#define all(x) (x).begin(), (x).end()
#define MT make_tuple
#define MP make_pair
#define lastOne(x) (31 - __builtin_clz(x))
#define debug(x) cout<<(#x)<<": \""<<x<<"\""<<endl
#define debugVec(vec) cout<<(#vec)<<": "; for (auto& i: vec) cout<<i<<" "; cout<<endl

typedef long long ll;
typedef pair<int, int> ii;
const double PI = 2*acos(0);
const double EPS =  1e-9;
const int oo = 1e9;
const ll MOD = 1e9+7;

int n, m;
const int N = 1e6+5;
int arr[N];
bool grid[N][4];
int dp[N][8];
int ok[8][8];

bool isValid(int mask1, int mask2)
{
    int &ret = ok[mask1][mask2];
    if (~ret)
        return ret;
    vector<string> grid2;
    if (n == 2)
    {
        grid2.push_back(bitset<2>(mask1).to_string());
        grid2.push_back(bitset<2>(mask2).to_string());
    }
    else if (n == 3)
    {
        grid2.push_back(bitset<3>(mask1).to_string());
        grid2.push_back(bitset<3>(mask2).to_string());
    }
    for (int c = 0; c < n-1; c++)
    {
        int cnt = 0;
        for (int i = 0; i < 2; i++)
            for (int j = c; j < c+2; j++)
                cnt += grid2[i][j] == '1';
        if (~cnt&1)
            return ret = false;
    }
    return ret = true;
}

int solve(int idx, int mask)
{
    if (idx == m-1)
        return 0;
    int & ret = dp[idx][mask];
    if (~ret)
        return ret;
    ret = oo;
    for (int m2 = 0; m2 < (1<<n); m2++)
    {
        if (isValid(mask, m2))
            ret = min(ret, solve(idx+1, m2)+__builtin_popcount(m2 ^ arr[idx+1]));
    }
    return ret;
}

int main()
{
    scanf("%d%d", &n, &m);
    if (n > m)
    {
        swap(n, m);
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                char x;
                scanf(" %c", &x);
                grid[j][i] = (x == '1');
            }
        }
    }
    else
    {
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                char x;
                scanf(" %c", &x);
                grid[i][j] = (x == '1');
            }
        }
    }
    int x = min(n, m);
    if (x >= 4)
        puts("-1");
    else if (x == 1)
        puts("0");
    else
    {
        memset(dp, -1, sizeof(dp));
        memset(ok, -1, sizeof(ok));
        for (int c = 0; c < m; c++)
        {
            arr[c] = 0;
            for (int r = 0; r < n; r++)
            {
                if (grid[r][c])
                    arr[c] |= (1<<r);
            }
        }

        int ans = oo;
        for (int i = 0; i < (1<<n); i++)
            ans = min(ans, solve(0, i)+__builtin_popcount(i ^ arr[0]));
        printf("%d\n", ans);
    }

    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define sc(x) scanf("%d", &(x))
#define sclld(x) scanf("%lld", &(x))
#define sz(x) int((x).size())
#define all(x) (x).begin(), (x).end()
#define MT make_tuple
#define MP make_pair
#define lastOne(x) (31 - __builtin_clz(x))
#define debug(x) cout<<(#x)<<": \""<<x<<"\""<<endl
#define debugVec(vec) cout<<(#vec)<<": "; for (auto& i: vec) cout<<i<<" "; cout<<endl

typedef long long ll;
typedef pair<int, int> ii;
const double PI = 2*acos(0);
const double EPS =  1e-9;
const int oo = 1e9;
const ll MOD = 1e9+7;

int n, m;
const int N = 1e6+5;
int arr[N];
bool grid[4][N];
int dp[N][8];
int ok[8][8];

bool isValid(int mask1, int mask2)
{
    int &ret = ok[mask1][mask2];
    if (~ret)
        return ret;
    vector<string> grid2;
    if (n == 2)
    {
        grid2.push_back(bitset<2>(mask1).to_string());
        grid2.push_back(bitset<2>(mask2).to_string());
    }
    else if (n == 3)
    {
        grid2.push_back(bitset<3>(mask1).to_string());
        grid2.push_back(bitset<3>(mask2).to_string());
    }
    for (int c = 0; c < n-1; c++)
    {
        int cnt = 0;
        for (int i = 0; i < 2; i++)
            for (int j = c; j < c+2; j++)
                cnt += grid2[i][j] == '1';
        if (~cnt&1)
            return ret = false;
    }
    return ret = true;
}

int solve(int idx, int mask)
{
    if (idx == m-1)
        return 0;
    int & ret = dp[idx][mask];
    if (~ret)
        return ret;
    ret = oo;
    for (int m2 = 0; m2 < (1<<n); m2++)
    {
        if (isValid(mask, m2))
            ret = min(ret, solve(idx+1, m2)+__builtin_popcount(m2 ^ arr[idx+1]));
    }
    return ret;
}

int main()
{
    scanf("%d%d", &n, &m);
    if (n > m)
    {
        swap(n, m);
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                char x;
                scanf(" %c", &x);
                grid[j][i] = (x == '1');
            }
        }
    }
    else
    {
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                char x;
                scanf(" %c", &x);
                grid[i][j] = (x == '1');
            }
        }
    }
    int x = min(n, m);
    if (x >= 4)
        puts("-1");
    else if (x == 1)
        puts("0");
    else
    {
        memset(dp, -1, sizeof(dp));
        memset(ok, -1, sizeof(ok));
        for (int c = 0; c < m; c++)
        {
            arr[c] = 0;
            for (int r = 0; r < n; r++)
            {
                if (grid[r][c])
                    arr[c] |= (1<<r);
            }
        }

        int ans = oo;
        for (int i = 0; i < (1<<n); i++)
            ans = min(ans, solve(0, i)+__builtin_popcount(i ^ arr[0]));
        printf("%d\n", ans);
    }

    return 0;
}


#pragma GCC optimize("O3")
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("unroll-loops")

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define int long long
#define pb push_back
#define pf push_front
#define eb emplace_back
#define mp make_pair
#define all(v) (v).begin(),(v).end()
#define rall(v) (v).rbegin(),(v).rend()
#define f first
#define s second
#define sz(x) (int)x.size()
#define endl "\n"
#define forn(i,n) for(int i=0;i<n;++i)
#define fore(i,l,r) for(int i=int(l);i<=int(r);++i)
#define rep(i,begin,end) for(__typeof(end) i=(begin);i!=(end);i++)
#define fill(a,value) memset(a,value,sizeof(a));
#define gcd(a,b) __gcd((a),(b))
#define watch1(x) cout<<(x)<<endl
#define watch2(x,y) cout<<(x)<<" "<<(y)<<endl
#define watch3(x,y,z) cout<<(x)<<" "<<(y)<<" "<<(z)<<endl
#define fastio ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);

typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<pii> vpii;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> oset;

const int INF = 9e18;
const int mod = 1e9 + 7;
const int N = 1e6 + 5;

int i,j,k,n,m,dp[N][1<<3],ok[1<<3][1<<3];
char a[4][N];

void solve()
{
    fill(dp,0);
    cin>>n>>m;
    if(n==1)
    {
        cout<<0;
        return;
    }
    if(n>3)
    {
        cout<<-1;
        return;
    }
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            cin>>a[i][j];
        }
    }
    for(i=0;i<(1<<n);i++)
    {
        for(j=0;j<(1<<n);j++)
        {
            ok[i][j]=0;
            int done=1;
            for(k=0;k<n-1;k++)
            {
                int total=0;
                if(i>>k&1)
                    total++;
                if(j>>k&1)
                    total++;
                if(i>>(k+1)&1)
                    total++;
                if(j>>(k+1)&1)
                    total++;
                if(!(total&1))
                    done=0;
            }
            if(done)
                ok[i][j]=1;
        }
    }
    for(i=1;i<=m;i++)
    {
        int val=0;
        for(j=0;j<n;j++)
        {
            if(a[j+1][i]=='1')
                val|=(1<<j);
        }
        for(int mask=0;mask<(1<<n);mask++)
        {
            dp[i][mask]=INF;
            for(int prev=0;prev<(1<<n);prev++)
            {
                if(ok[mask][prev])
                {
                    dp[i][mask]=min(dp[i][mask],dp[i-1][prev]+__builtin_popcountll(mask^val));
                }
            }
        }
    }
    int ans=INF;
    for(i=0;i<(1<<n);i++)
    {
        ans=min(ans,dp[m][i]);
    }
    cout<<ans;
}

signed main()
{
    fastio;
    int t;
    //cin>>t;
    t=1;
    while(t--)
    {
        solve();
    }
    return 0;
}


#pragma GCC optimize("O3")
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("unroll-loops")

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define int long long
#define pb push_back
#define pf push_front
#define eb emplace_back
#define mp make_pair
#define all(v) (v).begin(),(v).end()
#define rall(v) (v).rbegin(),(v).rend()
#define f first
#define s second
#define sz(x) (int)x.size()
#define endl "\n"
#define forn(i,n) for(int i=0;i<n;++i)
#define fore(i,l,r) for(int i=int(l);i<=int(r);++i)
#define rep(i,begin,end) for(__typeof(end) i=(begin);i!=(end);i++)
#define fill(a,value) memset(a,value,sizeof(a));
#define gcd(a,b) __gcd((a),(b))
#define watch1(x) cout<<(x)<<endl
#define watch2(x,y) cout<<(x)<<" "<<(y)<<endl
#define watch3(x,y,z) cout<<(x)<<" "<<(y)<<" "<<(z)<<endl
#define fastio ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);

typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<pii> vpii;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> oset;

const int INF = 9e18;
const int mod = 1e9 + 7;
const int N = 1e6 + 5;

int i,j,k,n,m,dp[N][1<<3],ok[1<<3][1<<3];
char a[3][N];

void solve()
{
    cin>>n>>m;
    if(n==1)
    {
        cout<<0;
        return;
    }
    if(n>3)
    {
        cout<<-1;
        return;
    }
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            cin>>a[i][j];
        }
    }
    for(i=0;i<(1<<n);i++)
    {
        for(j=0;j<(1<<n);j++)
        {
            ok[i][j]=0;
            int done=1;
            for(k=0;k<n-1;k++)
            {
                int total=0;
                if(i&(1<<k))
                    total++;
                if(i&(1<<(k+1)))
                    total++;
                if(j&(1<<k))
                    total++;
                if(j&(1<<(k+1)))
                    total++;
                if(!(total&1))
                    done=0;
            }
            if(done)
                ok[i][j]=1;
        }
    }
    for(i=0;i<(1<<n);i++)
    {
        int mask=0;
        for(j=1;j<=n;j++)
        {
            if(a[j][1]=='1')
                mask|=(1<<(j-1));
        }
        dp[1][i]=__builtin_popcount(mask^i);
    }
    for(i=2;i<=m;i++)
    {
        int val=0;
        for(j=1;j<=n;j++)
        {
            if(a[j][i]=='1')
                val|=(1<<(j-1));
        }
        for(int mask=0;mask<(1<<n);mask++)
        {
            dp[i][mask]=INF;
            for(int prev=0;prev<(1<<n);prev++)
            {
                if(ok[mask][prev])
                {
                    dp[i][mask]=min(dp[i][mask],dp[i-1][prev]+__builtin_popcount(mask^val));
                }
            }
        }
    }
    int ans=INF;
    for(i=0;i<(1<<n);i++)
    {
        ans=min(ans,dp[m][i]);
    }
    cout<<ans;
}

signed main()
{
    fastio;
    int t;
    //cin>>t;
    t=1;
    while(t--)
    {
        solve();
    }
    return 0;
}


#pragma GCC optimize("O3")
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("unroll-loops")

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define int long long
#define pb push_back
#define pf push_front
#define eb emplace_back
#define mp make_pair
#define all(v) (v).begin(),(v).end()
#define rall(v) (v).rbegin(),(v).rend()
#define f first
#define s second
#define sz(x) (int)x.size()
#define endl "\n"
#define forn(i,n) for(int i=0;i<n;++i)
#define fore(i,l,r) for(int i=int(l);i<=int(r);++i)
#define rep(i,begin,end) for(__typeof(end) i=(begin);i!=(end);i++)
#define fill(a,value) memset(a,value,sizeof(a));
#define gcd(a,b) __gcd((a),(b))
#define watch1(x) cout<<(x)<<endl
#define watch2(x,y) cout<<(x)<<" "<<(y)<<endl
#define watch3(x,y,z) cout<<(x)<<" "<<(y)<<" "<<(z)<<endl
#define fastio ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);

typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<pii> vpii;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> oset;

const int INF = 9e18;
const int mod = 1e9 + 7;
const int N = 1e6 + 5;

int i,j,k,n,m,dp[N][1<<3],ok[1<<3][1<<3];
char a[3][N];

void solve()
{
    cin>>n>>m;
    if(n==1)
    {
        cout<<0;
        return;
    }
    if(n>3)
    {
        cout<<-1;
        return;
    }
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            cin>>a[i][j];
        }
    }
    for(i=0;i<(1<<n);i++)
    {
        for(j=0;j<(1<<n);j++)
        {
            ok[i][j]=0;
            int done=1;
            for(k=0;k<n-1;k++)
            {
                int total=0;
                if(i>>k&1)
                    total++;
                if(j>>k&1)
                    total++;
                if(i>>(k+1)&1)
                    total++;
                if(j>>(k+1)&1)
                    total++;
                if(!(total&1))
                    done=0;
            }
            if(done)
                ok[i][j]=1;
        }
    }
    for(i=1;i<=m;i++)
    {
        int val=0;
        for(j=1;j<=n;j++)
        {
            if(a[j][i]=='1')
                val|=(1<<(j-1));
        }
        for(int mask=0;mask<(1<<n);mask++)
        {
            dp[i][mask]=INF;
            for(int prev=0;prev<(1<<n);prev++)
            {
                if(ok[mask][prev])
                {
                    dp[i][mask]=min(dp[i][mask],dp[i-1][prev]+__builtin_popcount(mask^val));
                }
            }
        }
    }
    int ans=INF;
    for(i=0;i<(1<<n);i++)
    {
        ans=min(ans,dp[m][i]);
    }
    cout<<ans;
}

signed main()
{
    fastio;
    int t;
    //cin>>t;
    t=1;
    while(t--)
    {
        solve();
    }
    return 0;
}


#pragma GCC optimize("O3")
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("unroll-loops")

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define int long long
#define pb push_back
#define pf push_front
#define eb emplace_back
#define mp make_pair
#define all(v) (v).begin(),(v).end()
#define rall(v) (v).rbegin(),(v).rend()
#define f first
#define s second
#define sz(x) (int)x.size()
#define endl "\n"
#define forn(i,n) for(int i=0;i<n;++i)
#define fore(i,l,r) for(int i=int(l);i<=int(r);++i)
#define rep(i,begin,end) for(__typeof(end) i=(begin);i!=(end);i++)
#define fill(a,value) memset(a,value,sizeof(a));
#define gcd(a,b) __gcd((a),(b))
#define watch1(x) cout<<(x)<<endl
#define watch2(x,y) cout<<(x)<<" "<<(y)<<endl
#define watch3(x,y,z) cout<<(x)<<" "<<(y)<<" "<<(z)<<endl
#define fastio ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);

typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<pii> vpii;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> oset;

const int INF = 9e18;
const int mod = 1e9 + 7;
const int N = 1e6 + 5;

int i,j,k,n,m,dp[N][1<<3],ok[1<<3][1<<3];
char a[3][N];

void solve()
{
    cin>>n>>m;
    if(n==1)
    {
        cout<<0;
        return;
    }
    if(n>3)
    {
        cout<<-1;
        return;
    }
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            cin>>a[i][j];
        }
    }
    for(i=0;i<(1<<n);i++)
    {
        for(j=0;j<(1<<n);j++)
        {
            ok[i][j]=0;
            int done=1;
            for(k=0;k<n-1;k++)
            {
                int total=0;
                if(i>>k&1)
                    total++;
                if(j>>k&1)
                    total++;
                if(i>>(k+1)&1)
                    total++;
                if(j>>(k+1)&1)
                    total++;
                if(!(total&1))
                    done=0;
            }
            if(done)
                ok[i][j]=1;
        }
    }
    for(i=0;i<(1<<n);i++)
    {
        int mask=0;
        for(j=1;j<=n;j++)
        {
            if(a[j][1]=='1')
                mask|=(1<<(j-1));
        }
        dp[1][i]=__builtin_popcount(mask^i);
    }
    for(i=2;i<=m;i++)
    {
        int val=0;
        for(j=1;j<=n;j++)
        {
            if(a[j][i]=='1')
                val|=(1<<(j-1));
        }
        for(int mask=0;mask<(1<<n);mask++)
        {
            dp[i][mask]=INF;
            for(int prev=0;prev<(1<<n);prev++)
            {
                if(ok[mask][prev])
                {
                    dp[i][mask]=min(dp[i][mask],dp[i-1][prev]+__builtin_popcount(mask^val));
                }
            }
        }
    }
    int ans=INF;
    for(i=0;i<(1<<n);i++)
    {
        ans=min(ans,dp[m][i]);
    }
    cout<<ans;
}

signed main()
{
    fastio;
    int t;
    //cin>>t;
    t=1;
    while(t--)
    {
        solve();
    }
    return 0;
}


#pragma GCC optimize("O3")
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("unroll-loops")

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define int long long
#define pb push_back
#define pf push_front
#define eb emplace_back
#define mp make_pair
#define all(v) (v).begin(),(v).end()
#define rall(v) (v).rbegin(),(v).rend()
#define f first
#define s second
#define sz(x) (int)x.size()
#define endl "\n"
#define forn(i,n) for(int i=0;i<n;++i)
#define fore(i,l,r) for(int i=int(l);i<=int(r);++i)
#define rep(i,begin,end) for(__typeof(end) i=(begin);i!=(end);i++)
#define fill(a,value) memset(a,value,sizeof(a));
#define gcd(a,b) __gcd((a),(b))
#define watch1(x) cout<<(x)<<endl
#define watch2(x,y) cout<<(x)<<" "<<(y)<<endl
#define watch3(x,y,z) cout<<(x)<<" "<<(y)<<" "<<(z)<<endl
#define fastio ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);

typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<pii> vpii;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> oset;

const int INF = 9e18;
const int mod = 1e9 + 7;
const int N = 1e6 + 5;

int i,j,k,n,m,dp[N][1<<3],ok[1<<3][1<<3];
char a[4][N];

void solve()
{
    cin>>n>>m;
    if(n==1)
    {
        cout<<0;
        return;
    }
    if(n>3)
    {
        cout<<-1;
        return;
    }
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            cin>>a[i][j];
        }
    }
    for(i=0;i<(1<<n);i++)
    {
        for(j=0;j<(1<<n);j++)
        {
            ok[i][j]=0;
            int done=1;
            for(k=0;k<n-1;k++)
            {
                int total=0;
                if(i&(1<<k))
                    total++;
                if(i&(1<<(k+1)))
                    total++;
                if(j&(1<<k))
                    total++;
                if(j&(1<<(k+1)))
                    total++;
                if(!(total&1))
                    done=0;
            }
            if(done)
                ok[i][j]=1;
        }
    }
    for(i=0;i<(1<<n);i++)
    {
        int mask=0;
        for(j=1;j<=n;j++)
        {
            if(a[j][1]=='1')
                mask|=(1<<(j-1));
        }
        dp[1][i]=__builtin_popcount(mask^i);
    }
    for(i=2;i<=m;i++)
    {
        int val=0;
        for(j=1;j<=n;j++)
        {
            if(a[j][i]=='1')
                val|=(1<<(j-1));
        }
        for(int mask=0;mask<(1<<n);mask++)
        {
            dp[i][mask]=INF;
            for(int prev=0;prev<(1<<n);prev++)
            {
                if(ok[mask][prev])
                {
                    dp[i][mask]=min(dp[i][mask],dp[i-1][prev]+__builtin_popcount(mask^val));
                }
            }
        }
    }
    int ans=INF;
    for(i=0;i<(1<<n);i++)
    {
        ans=min(ans,dp[m][i]);
    }
    cout<<ans;
}

signed main()
{
    fastio;
    int t;
    //cin>>t;
    t=1;
    while(t--)
    {
        solve();
    }
    return 0;
}


#pragma GCC optimize("O3")
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("unroll-loops")

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define int long long
#define pb push_back
#define pf push_front
#define eb emplace_back
#define mp make_pair
#define all(v) (v).begin(),(v).end()
#define rall(v) (v).rbegin(),(v).rend()
#define f first
#define s second
#define sz(x) (int)x.size()
#define endl "\n"
#define forn(i,n) for(int i=0;i<n;++i)
#define fore(i,l,r) for(int i=int(l);i<=int(r);++i)
#define rep(i,begin,end) for(__typeof(end) i=(begin);i!=(end);i++)
#define fill(a,value) memset(a,value,sizeof(a));
#define gcd(a,b) __gcd((a),(b))
#define watch1(x) cout<<(x)<<endl
#define watch2(x,y) cout<<(x)<<" "<<(y)<<endl
#define watch3(x,y,z) cout<<(x)<<" "<<(y)<<" "<<(z)<<endl
#define fastio ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);

typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<pii> vpii;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> oset;

const int INF = 9e18;
const int mod = 1e9 + 7;
const int N = 1e6 + 5;

int i,j,k,n,m,dp[N][1<<3],ok[1<<3][1<<3];
char a[3][N];

void solve()
{
    fill(dp,0);
    cin>>n>>m;
    if(n==1)
    {
        cout<<0;
        return;
    }
    if(n>3)
    {
        cout<<-1;
        return;
    }
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            cin>>a[i][j];
        }
    }
    for(i=0;i<(1<<n);i++)
    {
        for(j=0;j<(1<<n);j++)
        {
            ok[i][j]=0;
            int done=1;
            for(k=0;k<n-1;k++)
            {
                int total=0;
                if(i>>k&1)
                    total++;
                if(j>>k&1)
                    total++;
                if(i>>(k+1)&1)
                    total++;
                if(j>>(k+1)&1)
                    total++;
                if(!(total&1))
                    done=0;
            }
            if(done)
                ok[i][j]=1;
        }
    }
    for(i=1;i<=m;i++)
    {
        int val=0;
        for(j=1;j<=n;j++)
        {
            if(a[j][i]=='1')
                val|=(1<<(j-1));
        }
        for(int mask=0;mask<(1<<n);mask++)
        {
            dp[i][mask]=INF;
            for(int prev=0;prev<(1<<n);prev++)
            {
                if(ok[mask][prev])
                {
                    dp[i][mask]=min(dp[i][mask],dp[i-1][prev]+__builtin_popcount(mask^val));
                }
            }
        }
    }
    int ans=INF;
    for(i=0;i<(1<<n);i++)
    {
        ans=min(ans,dp[m][i]);
    }
    cout<<ans;
}

signed main()
{
    fastio;
    int t;
    //cin>>t;
    t=1;
    while(t--)
    {
        solve();
    }
    return 0;
}


#pragma GCC optimize("O3")
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("unroll-loops")

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define int long long
#define pb push_back
#define pf push_front
#define eb emplace_back
#define mp make_pair
#define all(v) (v).begin(),(v).end()
#define rall(v) (v).rbegin(),(v).rend()
#define f first
#define s second
#define sz(x) (int)x.size()
#define endl "\n"
#define forn(i,n) for(int i=0;i<n;++i)
#define fore(i,l,r) for(int i=int(l);i<=int(r);++i)
#define rep(i,begin,end) for(__typeof(end) i=(begin);i!=(end);i++)
#define fill(a,value) memset(a,value,sizeof(a));
#define gcd(a,b) __gcd((a),(b))
#define watch1(x) cout<<(x)<<endl
#define watch2(x,y) cout<<(x)<<" "<<(y)<<endl
#define watch3(x,y,z) cout<<(x)<<" "<<(y)<<" "<<(z)<<endl
#define fastio ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);

typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<pii> vpii;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> oset;

const int INF = 9e18;
const int mod = 1e9 + 7;
const int N = 1e6 + 5;

int i,j,k,n,m,dp[N][1<<3],ok[1<<3][1<<3];
char a[3][N];

void solve()
{
    cin>>n>>m;
    if(n==1)
    {
        cout<<0;
        return;
    }
    if(n>3)
    {
        cout<<-1;
        return;
    }
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            cin>>a[i][j];
        }
    }
    for(i=0;i<(1<<n);i++)
    {
        for(j=0;j<(1<<n);j++)
        {
            ok[i][j]=0;
            int done=1;
            for(k=0;k<n-1;k++)
            {
                int total=0;
                if(i&(1<<k))
                    total++;
                if(i&(1<<(k+1)))
                    total++;
                if(j&(1<<k))
                    total++;
                if(j&(1<<(k+1)))
                    total++;
                if(!(total&1))
                    done=0;
            }
            if(done)
                ok[i][j]=1;
        }
    }
    for(i=0;i<(1<<n);i++)
    {
        int mask=0;
        for(j=1;j<=n;j++)
        {
            if(a[1][j]=='1')
                mask|=(1<<(j-1));
        }
        dp[1][i]=__builtin_popcount(mask^i);
    }
    for(i=2;i<=m;i++)
    {
        int val=0;
        for(j=1;j<=n;j++)
        {
            if(a[i][j]=='1')
                val|=(1<<(j-1));
        }
        for(int mask=0;mask<(1<<n);mask++)
        {
            dp[i][mask]=INF;
            for(int prev=0;prev<(1<<n);prev++)
            {
                if(ok[mask][prev])
                {
                    dp[i][mask]=min(dp[i][mask],dp[i-1][prev]+__builtin_popcount(mask^val));
                }
            }
        }
    }
    int ans=INF;
    for(i=0;i<(1<<n);i++)
    {
        ans=min(ans,dp[m][i]);
    }
    cout<<ans;
}

signed main()
{
    fastio;
    int t;
    //cin>>t;
    t=1;
    while(t--)
    {
        solve();
    }
    return 0;
}


#pragma GCC optimize("O3")
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("unroll-loops")

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define int long long
#define pb push_back
#define pf push_front
#define eb emplace_back
#define mp make_pair
#define all(v) (v).begin(),(v).end()
#define rall(v) (v).rbegin(),(v).rend()
#define f first
#define s second
#define sz(x) (int)x.size()
#define endl "\n"
#define forn(i,n) for(int i=0;i<n;++i)
#define fore(i,l,r) for(int i=int(l);i<=int(r);++i)
#define rep(i,begin,end) for(__typeof(end) i=(begin);i!=(end);i++)
#define fill(a,value) memset(a,value,sizeof(a));
#define gcd(a,b) __gcd((a),(b))
#define watch1(x) cout<<(x)<<endl
#define watch2(x,y) cout<<(x)<<" "<<(y)<<endl
#define watch3(x,y,z) cout<<(x)<<" "<<(y)<<" "<<(z)<<endl
#define fastio ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);

typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<pii> vpii;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> oset;

const int INF = 9e18;
const int mod = 1e9 + 7;
const int N = 1e6 + 5;

int i,j,k,n,m,dp[N][1<<3],ok[1<<3][1<<3];
char a[3][N];

void solve()
{
    fill(dp,0);
    cin>>n>>m;
    if(n==1)
    {
        cout<<0;
        return;
    }
    if(n>3)
    {
        cout<<-1;
        return;
    }
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            cin>>a[i][j];
        }
    }
    for(i=0;i<(1<<n);i++)
    {
        for(j=0;j<(1<<n);j++)
        {
            ok[i][j]=0;
            int done=1;
            for(k=0;k<n-1;k++)
            {
                int total=0;
                if(i>>k&1)
                    total++;
                if(j>>k&1)
                    total++;
                if(i>>(k+1)&1)
                    total++;
                if(j>>(k+1)&1)
                    total++;
                if(!(total&1))
                    done=0;
            }
            if(done)
                ok[i][j]=1;
        }
    }
    for(i=1;i<=m;i++)
    {
        int val=0;
        for(j=1;j<=n;j++)
        {
            if(a[j][i]=='1')
                val|=(1<<(j-1));
        }
        for(int mask=0;mask<(1<<n);mask++)
        {
            dp[i][mask]=INF;
            for(int prev=0;prev<(1<<n);prev++)
            {
                if(ok[mask][prev])
                {
                    dp[i][mask]=min(dp[i][mask],dp[i-1][prev]+__builtin_popcountll(mask^val));
                }
            }
        }
    }
    int ans=INF;
    for(i=0;i<(1<<n);i++)
    {
        ans=min(ans,dp[m][i]);
    }
    cout<<ans;
}

signed main()
{
    fastio;
    int t;
    //cin>>t;
    t=1;
    while(t--)
    {
        solve();
    }
    return 0;
}


#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
char matrix[5][1000005];
bool isExist[1000005];
vector<int> v1, v2;
int check(int i, int j)
{
    return (matrix[i][j] == '1') + (matrix[i + 1][j] == '1') + (matrix[i][j + 1] == '1') + (matrix[i + 1][j + 1] == '1');
}
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    if (min(n, m) >= 4)
    {
        printf("-1\n");
        return 0;
    }
    if (n <= m)
    {
        for (int i = 0;i < n;i++)
        {
            for (int j = 0;j < m;j++)
            {
                scanf(" %c", &matrix[i][j]);
            }
        }
    }
    else
    {
        for (int i = 0;i < m;i++)
        {
            for (int j = 0;j < n;j++)
            {
                scanf(" %c", &matrix[i][j]);
            }
        }
    }

    if (n > m) swap(n, m);
    if (n == 1)
    {
        printf("0\n");
    }
    else
    {
        for (int i = 0;i < m - 1;i++)
        {
            if (check(0, i) % 2 == 0)
            {
                v1.push_back(i);
            }
        }
        if (n == 3)
        {
            for (int i = 0;i < m - 1;i++)
            {
                if (check(1, i) % 2 == 0) v2.push_back(i);
            }
        }
        sort(v1.begin(), v1.end());
        int ans1 = INF;
        int ans2 = INF;
        {
            int cnt = 0;
            int sz = (int)v1.size();
            if (v1[0] != 0)
            {
                cnt = 0;
                for (int i = 0;i < sz - 1 / 2;i++)
                {
                    if (i % 2 == 0) cnt += v1[i];
                    else cnt -= v1[i];
                }
                if (sz % 2 == 0)
                {
                    cnt -= (m - 1);
                }
                ans1 = min(ans1, cnt);
            }
            if (v1.back() != m - 1)
            {
                cnt = m - 1;
                for (int i = 0;i < sz - 1 / 2;i++)
                {
                    if (i % 2 == 0) cnt += v1[sz - i - 1];
                    else cnt -= v1[sz - i - 1];
                }
                ans1 = min(ans1, cnt);
            }
            cnt = 0;
            for (int i = 0;i < sz;i++)
            {
                if (i % 2 == 1) cnt += v1[i];
                else cnt -= v1[i];
            }
            ans1 = min(ans1, cnt);
        }
        if(n == 3)
        {
            int cnt = 0;
            int sz = (int)v2.size();
            if (v2[0] != 0)
            {
                cnt = 0;
                for (int i = 0;i < sz - 1 / 2;i++)
                {
                    if (i % 2 == 0) cnt += v2[i];
                    else cnt -= v2[i];
                }
                if (sz % 2 == 0)
                {
                    cnt -= (m - 1);
                }
                ans2 = min(ans2, cnt);
            }
            if (v2.back() != m - 1)
            {
                cnt = m - 1;
                for (int i = 0;i < sz - 1 / 2;i++)
                {
                    if (i % 2 == 0) cnt += v2[sz - i - 1];
                    else cnt -= v2[sz - i - 1];
                }
                ans2 = min(ans2, cnt);
            }
            cnt = 0;
            for (int i = 0;i < sz;i++)
            {
                if (i % 2 == 1) cnt += v2[i];
                else cnt -= v2[i];
            }
            ans2 = min(ans2, cnt);
        }
        if(n == 2) printf("%d\n", ans1);
        else printf("%d\n", ans1 + ans2);
    }

    return 0;
}


#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
int dp[1000005][8];
int matrix[4][1000005];
bool check3(int i, int j)
{
    int sum1 = ((i & 1) != 0) + ((i & 2) != 0) + ((j & 1) != 0) + ((j & 2) != 0);
    int sum2 = ((i & 4) != 0) + ((i & 2) != 0) + ((j & 4) != 0) + ((j & 2) != 0);
    return (sum1 % 2) && (sum2 % 2);
}
bool check2(int i, int j)
{
    int sum = ((i & 1) != 0) + ((i & 2) != 0) + ((j & 1) != 0) + ((j & 2) != 0);
    return (sum % 2 == 1);
}
bool is_valid(int i, int j, int n)
{
    if(n == 3) return check3(i, j);
    if(n == 2) return check2(i, j);
}
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    if(n >= 4)
    {
        printf("-1\n");
        return 0;
    }
    if(n == 1)
    {
        printf("0\n");
        return 0;
    }

    for(int i = 0;i < n;i++)
    {
        for(int j = 0;j < m;j++)
        {
            char c;
            scanf(" %c", &c);
            matrix[i][j] = c - '0';
        }
    }

    for(int i = 0;i < (1 << n);i++)
    {
        int msk = matrix[0][0] + matrix[1][0] * 2 + matrix[2][0] * 4;
        dp[0][i] = __builtin_popcount(i ^ msk);
    }

    for(int i = 1;i < m;i++)
    {
        int msk = matrix[0][i] + matrix[1][i] * 2 + matrix[2][i] * 4;
        for(int j = 0;j < (1 << n);j++)
        {
            dp[i][j] = INF;
            for(int k = 0;k < (1 << n);k++)
            {
                if(!is_valid(i, j, n)) continue;
                dp[i][j] = min(dp[i][j], dp[i - 1][k] + __builtin_popcount(j ^ msk));
            }
        }
    }

    int ans = INF;
    for(int i = 0;i < (1 << n);i++)
    {
        ans = min(ans, dp[m - 1][i]);
    }
    printf("%d\n", ans);

    return 0;
}


#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
int dp[1000005][8];
int matrix[4][1000005];
bool check3(int i, int j)
{
    int sum1 = ((i & 1) != 0) + ((i & 2) != 0) + ((j & 1) != 0) + ((j & 2) != 0);
    int sum2 = ((i & 4) != 0) + ((i & 2) != 0) + ((j & 4) != 0) + ((j & 2) != 0);
    return (sum1 % 2) && (sum2 % 2);
}
bool check2(int i, int j)
{
    int sum = ((i & 1) != 0) + ((i & 2) != 0) + ((j & 1) != 0) + ((j & 2) != 0);
    return (sum % 2 == 1);
}
bool is_valid(int i, int j, int n)
{
    if(n == 3) return check3(i, j);
    if(n == 2) return check2(i, j);
}
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    if(n >= 4)
    {
        printf("-1\n");
        return 0;
    }
    if(n == 1)
    {
        printf("0\n");
        return 0;
    }

    for(int i = 0;i < n;i++)
    {
        for(int j = 0;j < m;j++)
        {
            char c;
            scanf(" %c", &c);
            matrix[i][j] = c - '0';
        }
    }

    for(int i = 0;i < (1 << n);i++)
    {
        int msk = matrix[0][0] + matrix[1][0] * 2 + matrix[2][0] * 4;
        dp[0][i] = __builtin_popcount(i ^ msk);
    }

    for(int i = 1;i < m;i++)
    {
        int msk = matrix[0][i] + matrix[1][i] * 2 + matrix[2][i] * 4;
        for(int j = 0;j < (1 << n);j++)
        {
            dp[i][j] = INF;
            for(int k = 0;k < (1 << n);k++)
            {
                if(!is_valid(j, k, n)) continue;
                dp[i][j] = min(dp[i][j], dp[i - 1][k] + __builtin_popcount(j ^ msk));
            }
        }
    }

    int ans = INF;
    for(int i = 0;i < (1 << n);i++)
    {
        ans = min(ans, dp[m - 1][i]);
    }
    printf("%d\n", ans);

    return 0;
}


#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
char matrix[5][1000005];
bool isExist[1000005];
vector<int> v1, v2;
int check(int i, int j)
{
    return (matrix[i][j] == '1') + (matrix[i + 1][j] == '1') + (matrix[i][j + 1] == '1') + (matrix[i + 1][j + 1] == '1');
}
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    if (min(n, m) >= 4)
    {
        printf("-1\n");
        return 0;
    }
    if (n <= m)
    {
        for (int i = 0;i < n;i++)
        {
            for (int j = 0;j < m;j++)
            {
                scanf(" %c", &matrix[i][j]);
            }
        }
    }
    else
    {
        for (int i = 0;i < m;i++)
        {
            for (int j = 0;j < n;j++)
            {
                scanf(" %c", &matrix[i][j]);
            }
        }
    }

    if (n > m) swap(n, m);
    if (n == 1)
    {
        printf("0\n");
    }
    else
    {
        for (int i = 0;i < m - 1;i++)
        {
            if (check(0, i) % 2 == 0)
            {
                v1.push_back(i);
            }
        }
        if (n == 3)
        {
            for (int i = 0;i < m - 1;i++)
            {
                if (check(1, i) % 2 == 0) v2.push_back(i);
            }
        }
        sort(v1.begin(), v1.end());
        int ans1 = INF;
        int ans2 = INF;
        {
            int cnt = 0;
            int sz = (int)v1.size();
            if (v1[0] != 0)
            {
                cnt = 0;
                for (int i = 0;i < sz - 1 / 2;i++)
                {
                    if (i % 2 == 0) cnt += v1[i];
                    else cnt -= v1[i];
                }
                if (sz % 2 == 0)
                {
                    cnt -= (m - 1);
                }
                ans1 = min(ans1, cnt);
            }
            if (v1.back() != m - 1)
            {
                cnt = m - 1;
                for (int i = 0;i < sz - 1 / 2;i++)
                {
                    if (i % 2 == 0) cnt += v1[sz - i - 1];
                    else cnt -= v1[sz - i - 1];
                }
                ans1 = min(ans1, cnt);
            }
            cnt = 0;
            for (int i = 0;i < sz;i++)
            {
                if (i % 2 == 1) cnt += v1[i];
                else cnt -= v1[i];
            }
            if(v1.size() % 2 == 0) ans1 = min(ans1, cnt);
        }
        if(n == 3)
        {
            int cnt = 0;
            int sz = (int)v2.size();
            if (v2[0] != 0)
            {
                cnt = 0;
                for (int i = 0;i < sz - 1 / 2;i++)
                {
                    if (i % 2 == 0) cnt += v2[i];
                    else cnt -= v2[i];
                }
                if (sz % 2 == 0)
                {
                    cnt -= (m - 1);
                }
                ans2 = min(ans2, cnt);
            }
            if (v2.back() != m - 1)
            {
                cnt = m - 1;
                for (int i = 0;i < sz - 1 / 2;i++)
                {
                    if (i % 2 == 0) cnt += v2[sz - i - 1];
                    else cnt -= v2[sz - i - 1];
                }
                ans2 = min(ans2, cnt);
            }
            cnt = 0;
            for (int i = 0;i < sz;i++)
            {
                if (i % 2 == 1) cnt += v2[i];
                else cnt -= v2[i];
            }
            if(v2.size() % 2 == 0) ans2 = min(ans2, cnt);
        }
        if(n == 2) printf("%d\n", ans1);
        else printf("%d\n", ans1 + ans2);
    }

    return 0;
}


#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
int dp[1000005][8];
int matrix[4][1000005];
bool check(int i, int j)
{
    int sum1 = ((i & 1) != 0) + ((i & 2) != 0) + ((j & 1) != 0) + ((j & 2) != 0);
    int sum2 = ((i & 4) != 0) + ((i & 2) != 0) + ((j & 4) != 0) + ((j & 2) != 0);
    return (sum1 % 2) && (sum2 % 2);
}
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    if(n >= 4)
    {
        printf("-1\n");
        return 0;
    }
    if(n == 1)
    {
        printf("0\n");
        return 0;
    }

    for(int i = 0;i < n;i++)
    {
        for(int j = 0;j < m;j++)
        {
            char c;
            scanf(" %c", &c);
            matrix[i][j] = c - '0';
        }
    }

    for(int i = 0;i < 8;i++)
    {
        int msk = matrix[0][0] + matrix[1][0] * 2 + matrix[2][0] * 4;
        dp[0][i] = __builtin_popcount(i ^ msk);
    }

    for(int i = 1;i < m;i++)
    {
        int msk = matrix[0][i] + matrix[1][i] * 2 + matrix[2][i] * 4;
        for(int j = 0;j < 8;j++)
        {
            dp[i][j] = INF;
            for(int k = 0;k < 8;k++)
            {
                if(!check(j, k)) continue;
                dp[i][j] = min(dp[i][j], dp[i - 1][k] + __builtin_popcount(j ^ msk));
            }
        }
    }

    int ans = INF;
    for(int i = 0;i < 8;i++)
    {
        ans = min(ans, dp[m - 1][i]);
    }
    printf("%d\n", ans);

    return 0;
}


#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
char matrix[5][1000005];
bool isExist[1000005];
vector<int> v1, v2;
int check(int i, int j)
{
    return (matrix[i][j] == '1') + (matrix[i + 1][j] == '1') + (matrix[i][j + 1] == '1') + (matrix[i + 1][j + 1] == '1');
}
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    if (min(n, m) >= 4)
    {
        printf("-1\n");
        return 0;
    }
    if (n <= m)
    {
        for (int i = 0;i < n;i++)
        {
            for (int j = 0;j < m;j++)
            {
                scanf(" %c", &matrix[i][j]);
            }
        }
    }
    else
    {
        for (int i = 0;i < m;i++)
        {
            for (int j = 0;j < n;j++)
            {
                scanf(" %c", &matrix[i][j]);
            }
        }
    }

    if (n > m) swap(n, m);
    if (n == 1)
    {
        printf("0\n");
    }
    else
    {
        for (int i = 0;i < m - 1;i++)
        {
            if (check(0, i) % 2 == 0)
            {
                v1.push_back(i);
            }
        }
        if (n == 3)
        {
            for (int i = 0;i < m - 1;i++)
            {
                if (check(1, i) % 2 == 0) v2.push_back(i);
            }
        }
        sort(v1.begin(), v1.end());
        int ans1 = INF;
        int ans2 = INF;
        {
            int cnt = 0;
            int sz = (int)v1.size();
            if (v1[0] != 0)
            {
                cnt = 0;
                for (int i = 0;i < sz - 1 / 2;i++)
                {
                    if (i % 2 == 0) cnt += v1[i];
                    else cnt -= v1[i];
                }
                if (sz % 2 == 0)
                {
                    cnt -= (m - 1);
                }
                ans1 = min(ans1, cnt);
            }
            if (v1.back() != m - 1)
            {
                cnt = m - 1;
                for (int i = 0;i < sz - 1 / 2;i++)
                {
                    if (i % 2 == 0) cnt += v1[sz - i - 1];
                    else cnt -= v1[sz - i - 1];
                }
                ans1 = min(ans1, cnt);
            }
            cnt = 0;
            for (int i = 0;i < sz;i++)
            {
                if (i % 2 == 1) cnt += v1[i];
                else cnt -= v1[i];
            }

            ans1 = min(ans1, cnt);
        }
        if(n == 3)
        {
            int cnt = 0;
            int sz = (int)v2.size();
            if (v2[0] != 0)
            {
                cnt = 0;
                for (int i = 0;i < sz - 1 / 2;i++)
                {
                    if (i % 2 == 0) cnt += v2[i];
                    else cnt -= v2[i];
                }
                if (sz % 2 == 0)
                {
                    cnt -= (m - 1);
                }
                ans2 = min(ans2, cnt);
            }
            if (v2.back() != m - 1)
            {
                cnt = m - 1;
                for (int i = 0;i < sz - 1 / 2;i++)
                {
                    if (i % 2 == 0) cnt += v2[sz - i - 1];
                    else cnt -= v2[sz - i - 1];
                }
                ans2 = min(ans2, cnt);
            }
            cnt = 0;
            for (int i = 0;i < sz;i++)
            {
                if (i % 2 == 1) cnt += v2[i];
                else cnt -= v2[i];
            }
        }
        if(n == 2) printf("%d\n", ans1);
        else printf("%d\n", ans1 + ans2);
    }

    return 0;
}


/*
 * Author    : raj1307 - Raj Singh
 * Date      : 10.10.2020
 */

#pragma GCC optimize("Ofast")
// #pragma GCC optimize("unroll-loops")
// #define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;

#define fio ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define fr(i, a, b) for(int i = (a); i < (b); ++i)
#define fb(i, b, a) for(int i = (b); i > (a); --i)
#define fill(x,y) memset(x,y,sizeof(x))
#define rr return
#define mp make_pair
#define pb push_back
#define sz(x) ((int)x.size())
#define int long long
//#define ll long long
#define ld long double
#define S second
#define F first
#define endl "\n"
#define Endl "\n"
#define all(v) (v).begin(), (v).end()
typedef pair<int, int> pii;
int max(int a,int b){if(a>b) return a; else return b;}
int min(int a,int b){if(a>b) return b; else return a;}
int gcd(int a,int b){ return (b == 0) ? a : gcd(b, a % b);}
inline int lcm(int a,int b){ return a / gcd(a, b) * b;}
inline int normalize(int x,int mod){ x %= mod; if (x < 0) x += mod; return x;}

int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
string abc="abcdefghijklmnopqrstuvwxyz";
const double PI=acosl(-1);
const int mod = 1000*1000*1000+7;
//const int mod = 998244353;
const int inf = 1e18 +5;

//a and b are assumed to be taken modulo p
inline int add(int a, int b, int p = mod){ int c = a + b; if(c >= p) c -= p; return c; }
inline int sub(int a, int b, int p = mod){ int c = a - b; if(c < 0) c += p; return c; }
inline int mul(int a, int b, int p = mod){ return (a * 1ll * b) % p; }

// template<typename T>
// using ordered_set = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
//1. order_of_key(k) : number of elements strictly lesser than k
//2. find_by_order(k) : k-th element in the set
//To make it an ordered_multiset, use pairs of (value, time_of_insertion)
//to distinguish values which are similar.

int floor1(int n,int k){
    if(n%k == 0 || n >= 0)return n/k;
    return (n/k)-1;
}

int ceil1(int n,int k){
    return floor1(n+k-1,k);
}

int powm(int a, int b) {
    int res=1;
    while(b) {
        if(b&1)
            res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return res;
}

const int N = 1e6 + 5;

int n,m;
string s[N];
string t[N];

int cache[N][(1<<3) +5]; // changes

int dp(int pos,int last){

    if(pos==n)
        return 0;

    int &ans=cache[pos][last];
    if(ans!=-1)
        return ans;

    ans=inf;

    fr(cur,0,1<<m){

        fr(i,0,m){

            if(i+1<m){

                int x1=((1<<i)&last!=0);
                int x2=((1<<(i+1))&last!=0);
                int x3=((1<<i)&cur!=0);
                int x4=((1<<(i+1))&cur!=0);
                int cnt=x1+x2+x3+x4;

                //cout<<pos<<" "<<last<<" "<<cur<<" "<<cnt<<endl;

                if(cnt%2){

                    int changes= (x1!=(s[pos][i]-'0')) + (x1!=(s[pos][i+1]-'0'));
                    ans=min(ans,changes+dp(pos+1,cur));
                }

            }

        }

    }

    return ans;

}

void solve(){

    cin>>n>>m;
    fr(i,0,n){
        cin>>s[i];
    }

    //fill(cache,-1);
    // fr(i,0,n){
    //     fr(j,0,1<<m)
    //         cache[i][j]=-1;
    // }

    if(min(n,m)>3){
        cout<<-1;
        return;
    }

    if(n<m){

        fr(i,0,m){
            fr(j,0,n){
                t[i]+=s[j][i];
            }
        }
        fr(i,0,m){
            s[i]=t[i];
        }
        n=n+m-(m=n);
        cout<<n<<" "<<m<<endl;

    }

    int mn=n*m;

    if(m==4)
        cout<<-1;

    fr(i,0,1<<m){
        int ch=0;
        fr(j,0,m){
            if((1<<j)&i){
                if(s[0][j]=='0')
                    ++ch;
            }else{
                if(s[0][j]=='1')
                    ++ch;
            }

        }

        //cout<<ch<<" "<<i<<endl;

        mn=min(mn,ch+dp(1,i));
    }

    cout<<mn;

}

signed main() {
    fio;
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        //freopen("error.txt", "w", stderr);
    #endif
    cout<<fixed<<setprecision(10);
    int t=1;
    //cin>>t;  // UNCOMMENT FOR TEST-CASES
    //precompute();
    int cnt=1;
    while(t--) {
        //cout<<"Case #"<<cnt++<<": ";
        solve();
    }
    return 0;
}


/*
 * Author    : raj1307 - Raj Singh
 * Date      : 10.10.2020
 */

#pragma GCC optimize("Ofast")
// #pragma GCC optimize("unroll-loops")
// #define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;

#define fio ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define fr(i, a, b) for(int i = (a); i < (b); ++i)
#define fb(i, b, a) for(int i = (b); i > (a); --i)
#define fill(x,y) memset(x,y,sizeof(x))
#define rr return
#define mp make_pair
#define pb push_back
#define sz(x) ((int)x.size())
#define int long long
//#define ll long long
#define ld long double
#define S second
#define F first
#define endl "\n"
#define Endl "\n"
#define all(v) (v).begin(), (v).end()
typedef pair<int, int> pii;
int max(int a,int b){if(a>b) return a; else return b;}
int min(int a,int b){if(a>b) return b; else return a;}
int gcd(int a,int b){ return (b == 0) ? a : gcd(b, a % b);}
inline int lcm(int a,int b){ return a / gcd(a, b) * b;}
inline int normalize(int x,int mod){ x %= mod; if (x < 0) x += mod; return x;}

int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
string abc="abcdefghijklmnopqrstuvwxyz";
const double PI=acosl(-1);
const int mod = 1000*1000*1000+7;
//const int mod = 998244353;
const int inf = 1e18 +5;

//a and b are assumed to be taken modulo p
inline int add(int a, int b, int p = mod){ int c = a + b; if(c >= p) c -= p; return c; }
inline int sub(int a, int b, int p = mod){ int c = a - b; if(c < 0) c += p; return c; }
inline int mul(int a, int b, int p = mod){ return (a * 1ll * b) % p; }

// template<typename T>
// using ordered_set = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
//1. order_of_key(k) : number of elements strictly lesser than k
//2. find_by_order(k) : k-th element in the set
//To make it an ordered_multiset, use pairs of (value, time_of_insertion)
//to distinguish values which are similar.

int floor1(int n,int k){
    if(n%k == 0 || n >= 0)return n/k;
    return (n/k)-1;
}

int ceil1(int n,int k){
    return floor1(n+k-1,k);
}

int powm(int a, int b) {
    int res=1;
    while(b) {
        if(b&1)
            res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return res;
}

const int N = 1e6 + 5;

int n,m;
string s[N];
string t[N];

int cache[N][(1<<3) +5]; // changes

int dp(int pos,int last){

    if(pos==n)
        return 0;

    int &ans=cache[pos][last];
    if(ans!=-1)
        return ans;

    ans=inf;

    fr(cur,0,1<<m){

        fr(i,0,m){

            if(i+1<m){

                int x1=((1<<i)&last!=0);
                int x2=((1<<(i+1))&last!=0);
                int x3=((1<<i)&cur!=0);
                int x4=((1<<(i+1))&cur!=0);
                int cnt=x1+x2+x3+x4;

                //cout<<pos<<" "<<last<<" "<<cur<<" "<<cnt<<endl;

                if(cnt%2){

                    int changes= (x1!=(s[pos][i]-'0')) + (x1!=(s[pos][i+1]-'0'));
                    ans=min(ans,changes+dp(pos+1,cur));
                }

            }

        }

    }

    return ans;

}

void solve(){

    cin>>n>>m;
    fr(i,0,n){
        cin>>s[i];
    }

    //fill(cache,-1);
    fr(i,0,n){
        fr(j,0,1<<m)
            cache[i][j]=-1;
    }

    if(min(n,m)>3){
        cout<<-1;
        return;
    }

    if(n<m){

        fr(i,0,m){
            t[i]="";
            fr(j,0,n){
                t[i]+=s[j][i];
            }
        }
        fr(i,0,m){
            s[i]=t[i];
        }
        n=n+m-(m=n);

    }

    int mn=n*m;

    if(m==4)
        cout<<-1;

    fr(i,0,1<<m){
        int ch=0;
        fr(j,0,m){
            if((1<<j)&i){
                if(s[0][j]=='0')
                    ++ch;
            }else{
                if(s[0][j]=='1')
                    ++ch;
            }

        }

        //cout<<ch<<" "<<i<<endl;

        mn=min(mn,ch+dp(1,i));
    }

    cout<<mn;

}

signed main() {
    fio;
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        //freopen("error.txt", "w", stderr);
    #endif
    cout<<fixed<<setprecision(10);
    int t=1;
    //cin>>t;  // UNCOMMENT FOR TEST-CASES
    //precompute();
    int cnt=1;
    while(t--) {
        //cout<<"Case #"<<cnt++<<": ";
        solve();
    }
    return 0;
}


/*
 * Author    : raj1307 - Raj Singh
 * Date      : 10.10.2020
 */

#pragma GCC optimize("Ofast")
// #pragma GCC optimize("unroll-loops")
// #define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;

#define fio ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define fr(i, a, b) for(int i = (a); i < (b); ++i)
#define fb(i, b, a) for(int i = (b); i > (a); --i)
#define fill(x,y) memset(x,y,sizeof(x))
#define rr return
#define mp make_pair
#define pb push_back
#define sz(x) ((int)x.size())
#define int long long
//#define ll long long
#define ld long double
#define S second
#define F first
#define endl "\n"
#define Endl "\n"
#define all(v) (v).begin(), (v).end()
typedef pair<int, int> pii;
int max(int a,int b){if(a>b) return a; else return b;}
int min(int a,int b){if(a>b) return b; else return a;}
int gcd(int a,int b){ return (b == 0) ? a : gcd(b, a % b);}
inline int lcm(int a,int b){ return a / gcd(a, b) * b;}
inline int normalize(int x,int mod){ x %= mod; if (x < 0) x += mod; return x;}

int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
string abc="abcdefghijklmnopqrstuvwxyz";
const double PI=acosl(-1);
const int mod = 1000*1000*1000+7;
//const int mod = 998244353;
const int inf = 1e18 +5;

//a and b are assumed to be taken modulo p
inline int add(int a, int b, int p = mod){ int c = a + b; if(c >= p) c -= p; return c; }
inline int sub(int a, int b, int p = mod){ int c = a - b; if(c < 0) c += p; return c; }
inline int mul(int a, int b, int p = mod){ return (a * 1ll * b) % p; }

// template<typename T>
// using ordered_set = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
//1. order_of_key(k) : number of elements strictly lesser than k
//2. find_by_order(k) : k-th element in the set
//To make it an ordered_multiset, use pairs of (value, time_of_insertion)
//to distinguish values which are similar.

int floor1(int n,int k){
    if(n%k == 0 || n >= 0)return n/k;
    return (n/k)-1;
}

int ceil1(int n,int k){
    return floor1(n+k-1,k);
}

int powm(int a, int b) {
    int res=1;
    while(b) {
        if(b&1)
            res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return res;
}

const int N = 1e6 + 5;

int n,m;
string s[N];

//int cache[1<<9 +5][10]; // changes

int check(int x){

    string t="";
    fr(i,0,n*m){
        if((1<<i)&x)
            t+="1";
        else
            t+="0";
    }

    int ch=0;

    fr(i,0,n){
        fr(j,0,m){

            if(i+1<n and j+1<m){

                int cnt=t[i*m+j]-'0'+t[i*m+j+1]-'0'+t[(i+1)*m+j]-'0'+t[(i+1)*m+j+1]-'0';
                if(cnt%2==0)
                    return -1;
            }
        }
    }

    fr(i,0,n){
        fr(j,0,m){
            if(t[i*m+j]!=s[i][j])
                ++ch;
        }
    }

    return ch;

}

void solve(){

    cin>>n>>m;
    fr(i,0,n){
        cin>>s[i];
    }

    if(min(n,m)>3){
        cout<<-1;
        return;
    }

    int mn=n*m;
    fr(i,0,1<<(n*m)){

        int ch=check(i);
        if(ch!=-1)
            mn=min(mn,ch);
    }

    cout<<mn;

}

signed main() {
    fio;
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        //freopen("error.txt", "w", stderr);
    #endif
    cout<<fixed<<setprecision(10);
    int t=1;
    //cin>>t;  // UNCOMMENT FOR TEST-CASES
    //precompute();
    int cnt=1;
    while(t--) {
        //cout<<"Case #"<<cnt++<<": ";
        solve();
    }
    return 0;
}


/*
 * Author    : raj1307 - Raj Singh
 * Date      : 10.10.2020
 */

#pragma GCC optimize("Ofast")
// #pragma GCC optimize("unroll-loops")
// #define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;

#define fio ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define fr(i, a, b) for(int i = (a); i < (b); ++i)
#define fb(i, b, a) for(int i = (b); i > (a); --i)
#define fill(x,y) memset(x,y,sizeof(x))
#define rr return
#define mp make_pair
#define pb push_back
#define sz(x) ((int)x.size())
#define int long long
//#define ll long long
#define ld long double
#define S second
#define F first
#define endl "\n"
#define Endl "\n"
#define all(v) (v).begin(), (v).end()
typedef pair<int, int> pii;
int max(int a,int b){if(a>b) return a; else return b;}
int min(int a,int b){if(a>b) return b; else return a;}
int gcd(int a,int b){ return (b == 0) ? a : gcd(b, a % b);}
inline int lcm(int a,int b){ return a / gcd(a, b) * b;}
inline int normalize(int x,int mod){ x %= mod; if (x < 0) x += mod; return x;}

int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
string abc="abcdefghijklmnopqrstuvwxyz";
const double PI=acosl(-1);
const int mod = 1000*1000*1000+7;
//const int mod = 998244353;
const int inf = 1e18 +5;

//a and b are assumed to be taken modulo p
inline int add(int a, int b, int p = mod){ int c = a + b; if(c >= p) c -= p; return c; }
inline int sub(int a, int b, int p = mod){ int c = a - b; if(c < 0) c += p; return c; }
inline int mul(int a, int b, int p = mod){ return (a * 1ll * b) % p; }

// template<typename T>
// using ordered_set = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
//1. order_of_key(k) : number of elements strictly lesser than k
//2. find_by_order(k) : k-th element in the set
//To make it an ordered_multiset, use pairs of (value, time_of_insertion)
//to distinguish values which are similar.

int floor1(int n,int k){
    if(n%k == 0 || n >= 0)return n/k;
    return (n/k)-1;
}

int ceil1(int n,int k){
    return floor1(n+k-1,k);
}

int powm(int a, int b) {
    int res=1;
    while(b) {
        if(b&1)
            res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return res;
}

const int N = 1e6 + 5;

int n,m;
string s[N];
string t[N];

int cache[N][(1<<3) +5]; // pos,last

int dp(int pos,int last){

    if(pos==n)
        return 0;

    int &ans=cache[pos][last];
    if(ans!=-1)
        return ans;

    ans=inf;

    fr(cur,0,1<<m){

        int flag=1;

        fr(i,0,m){

            if(i+1<m){

                int cnt=0;

                if(((1<<i)&last)!=0) ++cnt;
                if(((1<<(i+1))&last)!=0)++cnt;
                if(((1<<i)&cur)!=0) ++cnt;
                if(((1<<(i+1))&cur)!=0) ++cnt;

                if(cnt%2==0){
                    flag=0;
                    break;
                }
            }

        }

        if(flag){

            int changes= 0;

            fr(i,0,m){
                if((1<<i)&cur){
                    if(s[pos][i]=='0')
                        ++changes;
                    }else{
                        if(s[pos][i]=='1')
                            ++changes;
                    }
            }

            ans=min(ans,changes+dp(pos+1,cur));
        }

    }
    return ans;

}

void solve(){

    cin>>n>>m;
    fr(i,0,n){
        cin>>s[i];
    }

    if(min(n,m)==1){
        cout<<0;
        return;
    }

    if(min(n,m)>3){
        cout<<-1;
        return;
    }

    if(n<m){

        fr(i,0,m){
            t[i]="";
            fr(j,0,n){
                t[i]+=s[j][i];
            }
        }
        fr(i,0,m){
            s[i]=t[i];
        }
        n=n+m-(m=n);

    }

    fr(i,0,n){
        fr(j,0,1<<m)
            cache[i][j]=-1;
    }

    int ans=n*m;

    fr(i,0,1<<m){
        int ch=0;
        fr(j,0,m){
            if((1<<j)&i){
                if(s[0][j]=='0')
                    ++ch;
            }else{
                if(s[0][j]=='1')
                    ++ch;
            }

        }

        ans=min(ans,ch+dp(1,i));
    }

    cout<<ans;

}

signed main() {
    fio;
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        //freopen("error.txt", "w", stderr);
    #endif
    cout<<fixed<<setprecision(10);
    int t=1;
    //cin>>t;  // UNCOMMENT FOR TEST-CASES
    //precompute();
    int cnt=1;
    while(t--) {
        //cout<<"Case #"<<cnt++<<": ";
        solve();
    }
    return 0;
}


/*
 * Author    : raj1307 - Raj Singh
 * Date      : 10.10.2020
 */

#pragma GCC optimize("Ofast")
// #pragma GCC optimize("unroll-loops")
// #define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;

#define fio ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define fr(i, a, b) for(int i = (a); i < (b); ++i)
#define fb(i, b, a) for(int i = (b); i > (a); --i)
#define fill(x,y) memset(x,y,sizeof(x))
#define rr return
#define mp make_pair
#define pb push_back
#define sz(x) ((int)x.size())
#define int long long
//#define ll long long
#define ld long double
#define S second
#define F first
#define endl "\n"
#define Endl "\n"
#define all(v) (v).begin(), (v).end()
typedef pair<int, int> pii;
int max(int a,int b){if(a>b) return a; else return b;}
int min(int a,int b){if(a>b) return b; else return a;}
int gcd(int a,int b){ return (b == 0) ? a : gcd(b, a % b);}
inline int lcm(int a,int b){ return a / gcd(a, b) * b;}
inline int normalize(int x,int mod){ x %= mod; if (x < 0) x += mod; return x;}

int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
string abc="abcdefghijklmnopqrstuvwxyz";
const double PI=acosl(-1);
const int mod = 1000*1000*1000+7;
//const int mod = 998244353;
const int inf = 1e18 +5;

//a and b are assumed to be taken modulo p
inline int add(int a, int b, int p = mod){ int c = a + b; if(c >= p) c -= p; return c; }
inline int sub(int a, int b, int p = mod){ int c = a - b; if(c < 0) c += p; return c; }
inline int mul(int a, int b, int p = mod){ return (a * 1ll * b) % p; }

// template<typename T>
// using ordered_set = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
//1. order_of_key(k) : number of elements strictly lesser than k
//2. find_by_order(k) : k-th element in the set
//To make it an ordered_multiset, use pairs of (value, time_of_insertion)
//to distinguish values which are similar.

int floor1(int n,int k){
    if(n%k == 0 || n >= 0)return n/k;
    return (n/k)-1;
}

int ceil1(int n,int k){
    return floor1(n+k-1,k);
}

int powm(int a, int b) {
    int res=1;
    while(b) {
        if(b&1)
            res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return res;
}

const int N = 1e6 + 5;

int n,m;
string s[N];
string t[N];

int cache[N][(1<<3) +5]; // changes

int dp(int pos,int last){

    if(pos==n)
        return 0;

    int &ans=cache[pos][last];
    if(ans!=-1)
        return ans;

    ans=inf;

    fr(cur,0,1<<m){

        fr(i,0,m){

            if(i+1<m){

                int cnt=0;

                if(((1<<i)&last)!=0) ++cnt;
                if(((1<<(i+1))&last)!=0)++cnt;
                if(((1<<i)&cur)!=0) ++cnt;
                if(((1<<(i+1))&cur)!=0) ++cnt;

                int x1=(((1<<i)&last)!=0);
                int x2=(((1<<(i+1))&last)!=0);
                int x3=(((1<<i)&cur)!=0);
                int x4=(((1<<(i+1))&cur)!=0);
                //int cnt=x1+x2+x3+x4;

                if(cnt%2){

                    int changes= 0;

                    if(x3!=(s[pos][i]-'0'))
                        ++changes;
                    if(x4!=(s[pos][i+1]-'0'));
                        ++changes;

                    ans=min(ans,changes+dp(pos+1,cur));
                }

            }

        }

    }

    return ans;

}

void solve(){

    cin>>n>>m;
    fr(i,0,n){
        cin>>s[i];
    }

    //fill(cache,-1);

    if(min(n,m)>3){
        cout<<-1;
        return;
    }

    if(n<m){

        fr(i,0,m){
            t[i]="";
            fr(j,0,n){
                t[i]+=s[j][i];
            }
        }
        fr(i,0,m){
            s[i]=t[i];
        }
        n=n+m-(m=n);
        // fr(i,0,n) cout<<s[i]<<endl;
        // cout<<n<<" "<<m<<endl;

    }

    fr(i,0,n){
        fr(j,0,1<<m)
            cache[i][j]=-1;
    }

    int mn=n*m;

    fr(i,0,1<<m){
        int ch=0;
        fr(j,0,m){
            if((1<<j)&i){
                if(s[0][j]=='0')
                    ++ch;
            }else{
                if(s[0][j]=='1')
                    ++ch;
            }

        }

        //cout<<ch<<" "<<i<<endl;

        mn=min(mn,ch+dp(1,i));
        //cout<<mn<<endl;
    }

    cout<<mn;

}

signed main() {
    fio;
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        //freopen("error.txt", "w", stderr);
    #endif
    cout<<fixed<<setprecision(10);
    int t=1;
    //cin>>t;  // UNCOMMENT FOR TEST-CASES
    //precompute();
    int cnt=1;
    while(t--) {
        //cout<<"Case #"<<cnt++<<": ";
        solve();
    }
    return 0;
}


/*
 * Author    : raj1307 - Raj Singh
 * Date      : 10.10.2020
 */

#pragma GCC optimize("Ofast")
// #pragma GCC optimize("unroll-loops")
// #define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;

#define fio ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define fr(i, a, b) for(int i = (a); i < (b); ++i)
#define fb(i, b, a) for(int i = (b); i > (a); --i)
#define fill(x,y) memset(x,y,sizeof(x))
#define rr return
#define mp make_pair
#define pb push_back
#define sz(x) ((int)x.size())
#define int long long
//#define ll long long
#define ld long double
#define S second
#define F first
#define endl "\n"
#define Endl "\n"
#define all(v) (v).begin(), (v).end()
typedef pair<int, int> pii;
int max(int a,int b){if(a>b) return a; else return b;}
int min(int a,int b){if(a>b) return b; else return a;}
int gcd(int a,int b){ return (b == 0) ? a : gcd(b, a % b);}
inline int lcm(int a,int b){ return a / gcd(a, b) * b;}
inline int normalize(int x,int mod){ x %= mod; if (x < 0) x += mod; return x;}

int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
string abc="abcdefghijklmnopqrstuvwxyz";
const double PI=acosl(-1);
const int mod = 1000*1000*1000+7;
//const int mod = 998244353;
const int inf = 1e18 +5;

//a and b are assumed to be taken modulo p
inline int add(int a, int b, int p = mod){ int c = a + b; if(c >= p) c -= p; return c; }
inline int sub(int a, int b, int p = mod){ int c = a - b; if(c < 0) c += p; return c; }
inline int mul(int a, int b, int p = mod){ return (a * 1ll * b) % p; }

// template<typename T>
// using ordered_set = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
//1. order_of_key(k) : number of elements strictly lesser than k
//2. find_by_order(k) : k-th element in the set
//To make it an ordered_multiset, use pairs of (value, time_of_insertion)
//to distinguish values which are similar.

int floor1(int n,int k){
    if(n%k == 0 || n >= 0)return n/k;
    return (n/k)-1;
}

int ceil1(int n,int k){
    return floor1(n+k-1,k);
}

int powm(int a, int b) {
    int res=1;
    while(b) {
        if(b&1)
            res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return res;
}

const int N = 1e6 + 5;

int n,m;
string s[N];
string t[N];

// int cache[N][1<<3 +5]; // changes

// int dp(int pos,int last){

//     if(pos==n)
//         return 0;

//     int &ans=cache[pos][last];
//     if(ans!=-1)
//         return ans;

//     ans=inf;

//     fr(cur,0,1<<m){

//         fr(i,0,m){

//             if(i+1<m){

//                 int x1=((1<<i)&last!=0);
//                 int x2=((1<<(i+1))&last!=0);
//                 int x3=((1<<i)&cur!=0);
//                 int x4=((1<<(i+1))&cur!=0);
//                 int cnt=x1+x2+x3+x4;

//                 //cout<<pos<<" "<<last<<" "<<cur<<" "<<cnt<<endl;

//                 if(cnt%2){

//                     int changes= (x1!=(s[pos][i]-'0')) + (x1!=(s[pos][i+1]-'0'));
//                     ans=min(ans,changes+dp(pos+1,cur));
//                 }

//             }

//         }

//     }

//     return ans;

// }

void solve(){

    cin>>n>>m;
    fr(i,0,n){
        cin>>s[i];
    }

    //fill(cache,-1);
    // fr(i,0,n){
    //     fr(j,0,1<<m)
    //         cache[i][j]=-1;
    // }

    if(min(n,m)>3){
        cout<<-1;
        return;
    }

    if(n<m){

        fr(i,0,m){
            fr(j,0,n){
                t[i]+=s[j][i];
            }
        }
        fr(i,0,m){
            s[i]=t[i];
        }
        n=n+m-(m=n);
        cout<<n<<" "<<m<<endl;

    }

    int mn=n*m;

    if(m==4)
        cout<<-1;

    fr(i,0,1<<m){
        int ch=0;
        fr(j,0,m){
            if((1<<j)&i){
                if(s[0][j]=='0')
                    ++ch;
            }else{
                if(s[0][j]=='1')
                    ++ch;
            }

        }

        //cout<<ch<<" "<<i<<endl;

        //mn=min(mn,ch+dp(1,i));
    }

    cout<<mn;

}

signed main() {
    fio;
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        //freopen("error.txt", "w", stderr);
    #endif
    cout<<fixed<<setprecision(10);
    int t=1;
    //cin>>t;  // UNCOMMENT FOR TEST-CASES
    //precompute();
    int cnt=1;
    while(t--) {
        //cout<<"Case #"<<cnt++<<": ";
        solve();
    }
    return 0;
}