import java.util.*;
import java.io.*;

public class R554D
{

	static long mod = (long)(1e9)+7;
	static long[] fact = new long[3000];
	static int n;
	static long[][][] memo;

    public static void main (String[] args)
    {
        JS scan = new JS();
        n = scan.nextInt();
        memo = new long[2][n+1][n+1];
        for(int i = 0; i < 2; i++){
        	for(int j = 0; j <= n; j++){
        		Arrays.fill(memo[i][j], -1);
        	}
        }
        System.out.println(solve(0, 0, 0)); //DON'T SUBMIT BEFORE YOU MOD
    }

    static long solve(int cant, int i, int j){
    	if(memo[cant][i][j] != -1) return memo[cant][i][j];
    	long resNoTake = 0;
    	if(i < n) resNoTake += solve(0, i+1, j);
    	if(j < i) resNoTake += solve(0, i, j+1);
    	resNoTake %= mod;
    	if(cant == 1) return memo[cant][i][j] = resNoTake;

    	long resTake = 0;
    	long op1 = 0;
    	long op2 = 0;
    	if(i < n){
    		op1 = 1+solve(1, i+1, j);
    		if(j < i){
    			op1 += solve(0, i, j+1);
    		}
    		op1 %= mod;
    	}
    	if(j < i){
    		op2 = 1+solve(1, i, j+1);
    		if(i < n){
    			op2 += solve(0, i+1, j);
    		}
    		op2 %= mod;
    	}
    	resTake = Math.max(op1, op2);

    	return memo[cant][i][j] = Math.max(resTake, resNoTake);
    }

    static long power(long x, long y, long p)
    {
        // Initialize result
    	long res = 1;

        // Update x if it is more than or
        // equal to p
        x = x % p;

        while (y > 0)
        {

            // If y is odd, multiply x
            // with result
            if (y % 2 == 1)
                res = (res * x) % p;

            // y must be even now
            y = y >> 1; // y = y/2
            x = (x * x) % p;
        }
        return res;
    }

    // Returns n^(-1) mod p
    static long modInverse(long n, long p)
    {
        return power(n, p-2, p);
    }

	static void _printParenthesis(char str[], int pos, int n, int open, int close)
    {
        if(close == n)
        {
            // print the possible combinations
            for(int i=0;i<str.length;i++)
                System.out.print(str[i]);
            System.out.println();
            return;
        }
        else
        {
            if(open > close) {
                str[pos] = '}';
                _printParenthesis(str, pos+1, n, open, close+1);
            }
            if(open < n) {
                str[pos] = '{';
                _printParenthesis(str, pos+1, n, open+1, close);
            }
        }
    }

    // Wrapper over _printParenthesis()
    static void printParenthesis(char str[], int n)
    {
        if(n > 0)
        _printParenthesis(str, 0, n, 0, 0);
        return;
    }

	static class JS{
		public int BS = 1<<16;
		public char NC = (char)0;
		byte[] buf = new byte[BS];
		int bId = 0, size = 0;
		char c = NC;
		double num = 1;
		BufferedInputStream in;

		public JS() {
			in = new BufferedInputStream(System.in, BS);
		}

		public JS(String s) throws FileNotFoundException {
			in = new BufferedInputStream(new FileInputStream(new File(s)), BS);
		}

		public char nextChar(){
			while(bId==size) {
				try {
					size = in.read(buf);
				}catch(Exception e) {
					return NC;
				}
				if(size==-1)return NC;
				bId=0;
			}
			return (char)buf[bId++];
		}

		public int nextInt() {
			return (int)nextLong();
		}

		public long nextLong() {
			num=1;
			boolean neg = false;
			if(c==NC)c=nextChar();
			for(;(c<'0' || c>'9'); c = nextChar()) {
				if(c=='-')neg=true;
			}
			long res = 0;
			for(; c>='0' && c <='9'; c=nextChar()) {
				res = (res<<3)+(res<<1)+c-'0';
				num*=10;
			}
			return neg?-res:res;
		}

		public double nextDouble() {
			double cur = nextLong();
			return c!='.' ? cur:cur+nextLong()/num;
		}

		public String next() {
			StringBuilder res = new StringBuilder();
			while(c<=32)c=nextChar();
			while(c>32) {
				res.append(c);
				c=nextChar();
			}
			return res.toString();
		}

		public String nextLine() {
			StringBuilder res = new StringBuilder();
			while(c<=32)c=nextChar();
			while(c!='\n') {
				res.append(c);
				c=nextChar();
			}
			return res.toString();
		}

		public boolean hasNext() {
			if(c>32)return true;
			while(true) {
				c=nextChar();
				if(c==NC)return false;
				else if(c>32)return true;
			}
		}
	}
}


import java.io.*;
import java.util.*;

public class B {

	static int n,MOD=(int)1e9+7;
	static int [][][]memo;
	static int dp(int balance,int length,int free) {

		int open=balance + (length-balance)/2;
		if(length==2*n)
			return 0;
		if(memo[free][balance][length]!=-1)
			return memo[free][balance][length];
		int ans=0;
		if(open<n) {
			ans += Math.max(dp(balance+1,length+1, 1),dp(balance+1,length+1,free^1)+free);
			if(ans>=MOD)
				ans-=MOD;
		}
		if(balance>0) {
			int x=+open<n?0:free;
			ans += Math.max(dp(balance-1,length+1, 1),dp(balance-1,length+1,x^1)+x);
			if(ans>=MOD)
				ans-=MOD;
		}
		return memo[free][balance][length]=ans;

	}
	public static void main(String[] args) throws IOException {
		Scanner sc = new Scanner();
		PrintWriter out = new PrintWriter(System.out);
		n=sc.nextInt();
		memo=new int [2][n+1][2*n+1];
		for(int i=0;i<2;i++)
			for(int j=0;j<=n;j++)
				Arrays.fill(memo[i][j], -1);
		out.println(dp(0,0,1));
		out.close();

	}

	static class Scanner {
		BufferedReader br;
		StringTokenizer st;

		Scanner() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}

		Scanner(String fileName) throws FileNotFoundException {
			br = new BufferedReader(new FileReader(fileName));
		}

		String next() throws IOException {
			while (st == null || !st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

		String nextLine() throws IOException {
			return br.readLine();
		}

		int nextInt() throws IOException {
			return Integer.parseInt(next());
		}

		long nextLong() throws NumberFormatException, IOException {
			return Long.parseLong(next());
		}

		double nextDouble() throws NumberFormatException, IOException {
			return Double.parseDouble(next());
		}

	}

}


import java.util.*;
import java.io.*;
import static java.lang.Math.*;
public class Main {
    static final long MOD = 1_000_000_007 , INF = 1_000_000_000_000_000L;
    static final int INf = 1_000_000_000;
    static FastReader reader;
    static PrintWriter writer;
    public static void main(String[] args) {
        Thread t = new Thread(null, new O(), "Integer.MAX_VALUE", 100000000);
        t.start();
    }
    static class O implements Runnable {
        public void run() {
            try {
                magic();
            }
            catch (Exception e) {
                e.printStackTrace();
                System.exit(1);
            }
        }
    }
    static class FastReader {
        final private int BUFFER_SIZE = 1 << 16;
        private DataInputStream din;
        private byte[] buffer;
        private int bufferPointer, bytesRead;

        public FastReader() {
            din = new DataInputStream(System.in);
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public FastReader(String file_name) throws IOException {
            din = new DataInputStream(new FileInputStream(file_name));
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public String readLine() throws IOException {
            byte[] buf = new byte[1000000];
            int cnt = 0, c;
            while ((c = read()) != -1) {
                if (c == '\n') break;
                buf[cnt++] = (byte) c;
            }
            return new String(buf, 0, cnt);
        }

        public int nextInt() throws IOException {
            int ret = 0;
            byte c = read();
            while (c <= ' ') c = read();
            boolean neg = (c == '-');
            if (neg) c = read();
            do {
                ret = ret * 10 + c - '0';
            } while ((c = read()) >= '0' && c <= '9');
            if (neg) return -ret;
            return ret;
        }

        public long nextLong() throws IOException {
            long ret = 0;
            byte c = read();
            while (c <= ' ') c = read();
            boolean neg = (c == '-');
            if (neg) c = read();
            do {
                ret = ret * 10 + c - '0';
            } while ((c = read()) >= '0' && c <= '9');
            if (neg) return -ret;
            return ret;
        }

        public double nextDouble() throws IOException {
            double ret = 0, div = 1;
            byte c = read();
            while (c <= ' ') c = read();
            boolean neg = (c == '-');
            if (neg) c = read();
            do {
                ret = ret * 10 + c - '0';
            } while ((c = read()) >= '0' && c <= '9');
            if (c == '.') while ((c = read()) >= '0' && c <= '9') ret += (c - '0') / (div *= 10);
            if (neg) return -ret;
            return ret;
        }

        private void fillBuffer() throws IOException {
            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
            if (bytesRead == -1) buffer[0] = -1;
        }

        private byte read() throws IOException {
            if (bufferPointer == bytesRead) fillBuffer();
            return buffer[bufferPointer++];
        }

        public void close() throws IOException {
            if (din == null) return;
            din.close();
        }
    }
    static int n;
    static Pair dp[][];
    static void magic() throws IOException {
        reader = new FastReader();
        writer = new PrintWriter(System.out, true);
        n = reader.nextInt();
        dp = new Pair[2 * n + 1][2 * n + 1];
        writer.println(f(0,0).ans);

    }
    static Pair f(int idx, int open_count) {
        if(idx==2*n) {
            if(open_count==0) {
                return new Pair(0, true);
            }
            else {
                return new Pair(0, false);
            }
        }
        if(dp[idx][open_count]!=null) {
            return dp[idx][open_count];
        }
        Pair left = new Pair(0, false);
        int udhar = 2*n - idx - 1;
        if(udhar>open_count) {
            left = f(idx+1, open_count+1);
        }
        Pair right = open_count>0 ? f(idx+1, open_count-1) : new Pair(0, false);
        if(left.free || right.free) {
            return dp[idx][open_count] = new Pair((int)((left.ans+right.ans+1)%MOD), false);
        }
        else {
            return dp[idx][open_count] = new Pair((int)((left.ans+right.ans)%MOD), true);
        }
    }
    static class Pair {
        int ans;
        boolean free;
        Pair(int ans, boolean free) {
            this.ans = ans;
            this.free = free;
        }
    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Rustam Musin (t.me/musin_acm)
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        DNekoIPrank solver = new DNekoIPrank();
        solver.solve(1, in, out);
        out.close();
    }

    static class DNekoIPrank {
        int mod = (int) 1e9 + 7;

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int n = in.readInt();
            int ans = new Solve().solve(n);
            out.print(ans);
        }

        class Solve {
            int solve(int n) {
                int[][][] dp = new int[2 * n + 1][2 * n + 1][2];
                dp[0][0][0] = 1;
                for (int depth = 1; depth <= 2 * n; depth++) {
                    for (int opened = depth & 1; opened <= depth; opened += 2) {
                        if (opened - 1 >= 0) {
                            dp[depth][opened][0] += dp[depth - 1][opened - 1][1];
                            dp[depth][opened][1] += dp[depth - 1][opened - 1][0];
                        }
                        if (opened + 1 <= n) {
                            dp[depth][opened][0] += dp[depth - 1][opened + 1][1];
                            dp[depth][opened][1] += dp[depth - 1][opened + 1][0];
                        }
                        dp[depth][opened][0]++;
                        dp[depth][opened][0] %= mod;
                        dp[depth][opened][1] %= mod;
                    }
                }
                return dp[2 * n][0][1];
            }

        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void close() {
            writer.close();
        }

        public void print(int i) {
            writer.print(i);
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }
}


import java.lang.*;
import java.math.*;
import java.util.*;
import java.io.*;
public class Main {
    void solve() {
        n=ni();
        dp=new int[2*n+1][n+1][2];
        for(int i=1;i<=2*n;i++) for(int j=0;j<=n;j++) Arrays.fill(dp[i][j],-1);
        int ans=go(1,0,0);
        pw.println(ans);
    }
    int dp[][][];
    int n;
    int go(int i,int j,int taken){
        if(j<0 || j>n) return Integer.MIN_VALUE;
        if(i>2*n){
            if(j==0) return 0;
            return Integer.MIN_VALUE;
        }
     //   pw.println(i+" "+j+" "+dp[i][j][taken]);
        if(dp[i][j][taken]!=-1) return dp[i][j][taken];

        int cc=Integer.MIN_VALUE,d1=-1,d2=-1;

            d1=go(i+1,j+1,0);
            d2=go(i+1,j-1,0);
            if(d1==Integer.MIN_VALUE && d2==Integer.MIN_VALUE){

            }else {
                d1=Math.max(0,d1);
                d2=Math.max(0,d2);
                cc=add(d1,d2);
            }
            if(taken==0){
            d1=go(i+1,j+1,1);
            d2=go(i+1,j-1,1);
            if(d1==Integer.MIN_VALUE && d2==Integer.MIN_VALUE){

            }else {
                d1=Math.max(0,d1);
                d2=Math.max(0,d2);
                cc=Math.max(cc,add(1,add(d1,d2)));
            }

        }
        dp[i][j][taken]=cc;
        return cc;
    }

    int add(long a,long b){
        a+=b;
        if(a>=M)a-=M;
        return (int)a;
    }

    long M =(long)1e9+7;
    InputStream is;
    PrintWriter pw;
    String INPUT = "";

    void run() throws Exception {
        is = INPUT.isEmpty() ? System.in : new ByteArrayInputStream(INPUT.getBytes());
        pw = new PrintWriter(System.out);
        long s = System.currentTimeMillis();
        solve();
        pw.flush();
        if (!INPUT.isEmpty()) tr(System.currentTimeMillis() - s + "ms");

    }

    public static void main(String[] args) throws Exception {
        new Main().run();
    }

    private byte[] inbuf = new byte[1024];
    public int lenbuf = 0, ptrbuf = 0;

    private int readByte() {
        if (lenbuf == -1) throw new InputMismatchException();
        if (ptrbuf >= lenbuf) {
            ptrbuf = 0;
            try {
                lenbuf = is.read(inbuf);
            } catch (IOException e) {
                throw new InputMismatchException();
            }
            if (lenbuf <= 0) return -1;
        }
        return inbuf[ptrbuf++];
    }

    private boolean isSpaceChar(int c) {
        return !(c >= 33 && c <= 126);
    }

    private int skip() {
        int b;
        while ((b = readByte()) != -1 && isSpaceChar(b)) ;
        return b;
    }

    private double nd() {
        return Double.parseDouble(ns());
    }

    private char nc() {
        return (char) skip();
    }

    private String ns() {
        int b = skip();
        StringBuilder sb = new StringBuilder();
        while (!(isSpaceChar(b))) { // when nextLine, (isSpaceChar(b) && b != ' ')
            sb.appendCodePoint(b);
            b = readByte();
        }
        return sb.toString();
    }

    private char[] ns(int n) {
        char[] buf = new char[n];
        int b = skip(), p = 0;
        while (p < n && !(isSpaceChar(b))) {
            buf[p++] = (char) b;
            b = readByte();
        }
        return n == p ? buf : Arrays.copyOf(buf, p);
    }

    private char[][] nm(int n, int m) {
        char[][] map = new char[n][];
        for (int i = 0; i < n; i++) map[i] = ns(m);
        return map;
    }

    private int[] na(int n) {
        int[] a = new int[n];
        for (int i = 0; i < n; i++) a[i] = ni();
        return a;
    }

    private int ni() {
        int num = 0, b;
        boolean minus = false;
        while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-')) ;
        if (b == '-') {
            minus = true;
            b = readByte();
        }

        while (true) {
            if (b >= '0' && b <= '9') {
                num = num * 10 + (b - '0');
            } else {
                return minus ? -num : num;
            }
            b = readByte();
        }
    }

    private long nl() {
        long num = 0;
        int b;
        boolean minus = false;
        while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-')) ;
        if (b == '-') {
            minus = true;
            b = readByte();
        }

        while (true) {
            if (b >= '0' && b <= '9') {
                num = num * 10 + (b - '0');
            } else {
                return minus ? -num : num;
            }
            b = readByte();
        }
    }

    private boolean oj = System.getProperty("ONLINE_JUDGE") != null;

    private void tr(Object... o) {
        if (INPUT.length() > 0) System.out.println(Arrays.deepToString(o));
    }

}


import java.util.*;
import java.io.*;

public class Main {
	public static void main(String args[]) {new Main().run();}

	FastReader in = new FastReader();
	PrintWriter out = new PrintWriter(System.out);
	void run(){
		work();
		out.flush();
	}
	long mod=1000000007;
	long gcd(long a,long b) {
		return a==0?b:b>a?gcd(b%a,a):gcd(b,a);
	}
	void work() {
		int n=in.nextInt();
		long[] dp=new long[2*n+1];
		long ret=0;
		dp[0]=1;
		for(int p=1;p<=2*n;p++) {
			long[] ndp=new long[2*n+1];
			for(int i=0;i<2*n;i++) {
				ndp[i+1]+=dp[i];
				ndp[i+1]%=mod;
				if(i-1>=0) {
					ndp[i-1]+=dp[i];
					ndp[i-1]%=mod;
					if(p%2==0) {
						int r=2*n-p;
						if(r>=i-1) {
							ret+=dp[i];
						}
					}
				}
			}
			ret%=mod;
			dp=ndp;
		}
		out.println(ret);
	}
}

class FastReader
{
	BufferedReader br;
	StringTokenizer st;

	public FastReader()
	{
		br=new BufferedReader(new InputStreamReader(System.in));
	}

	public String next()
	{
		if(st==null || !st.hasMoreElements())
		{
			try {
				st = new StringTokenizer(br.readLine());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return st.nextToken();
	}

	public int nextInt()
	{
		return Integer.parseInt(next());
	}

	public long nextLong()
	{
		return Long.parseLong(next());
	}
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Rustam Musin (t.me/musin_acm)
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        DNekoIPrank solver = new DNekoIPrank();
        solver.solve(1, in, out);
        out.close();
    }

    static class DNekoIPrank {
        int mod = (int) 1e9 + 7;

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int n = in.readInt();
            int ans = new Solve().solve(n);
            out.print(ans);
        }

        class Solve {
            int solve(int n) {
                int[][][] dp = new int[2 * n + 1][2 * n + 1][2];
                dp[0][0][0] = 1;
                for (int depth = 1; depth <= 2 * n; depth++) {
                    for (int opened = depth & 1; opened <= depth; opened += 2) {
                        if (opened - 1 >= 0) {
                            dp[depth][opened][0] += dp[depth - 1][opened - 1][1];
                            dp[depth][opened][1] += dp[depth - 1][opened - 1][0];
                        }
                        if (opened + 1 < dp[depth - 1].length) {
                            dp[depth][opened][0] += dp[depth - 1][opened + 1][1];
                            dp[depth][opened][1] += dp[depth - 1][opened + 1][0];
                        }
                        dp[depth][opened][0]++;
                        dp[depth][opened][0] %= mod;
                        dp[depth][opened][1] %= mod;
                    }
                }
                return dp[2 * n][0][1];
            }

        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void close() {
            writer.close();
        }

        public void print(int i) {
            writer.print(i);
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }
}


import java.util.Scanner;

public class Main {
    private static Scanner sc = new Scanner(System.in);
    private static int mod = 1000000007;
    public static void main(String[] args) {
        int [][]dp = new int[2005][22005];
        int [][]ok = new int[2005][2005];
        ok[0][0] = 1;
        for(int i = 1; i <= 2000; i++){
            for(int j = i & 1; j <= i; j += 2){
                if(j == 0) {
                    dp[i][j] = dp[i - 1][j + 1];
                    if(ok[i - 1][j + 1] == 1)
                        dp[i][j] = (dp[i][j] + 1) % mod;
                    else
                        ok[i][j] = 1;
                    continue;
                }
                dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j + 1]) % mod;
                if(ok[i - 1][j + 1] == 1 || ok[i - 1][j - 1] == 1)
                    dp[i][j] = (dp[i][j] + 1) % mod;
                else
                    ok[i][j] = 1;

            }
        }
        System.out.print(dp[2 * sc.nextInt()][0]);
    }

}


import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Scanner;

import static java.lang.Math.max;

public class D {
    static int n;
    static long dp[][][], mod = (long) 1e9 + 7, inf = (long) 1e18;

    public static void main(String[] args) throws Exception {
        Scanner in = new Scanner(System.in);
        PrintWriter pw = new PrintWriter(System.out);
        n = in.nextInt();
        dp = new long[2][n + n + 1][n + n + 1];
        for (long a[][] : dp) for (long b[] : a) Arrays.fill(b, -1);
        pw.println(solve(0, 0, 0));
        pw.close();
    }

    static long solve(int last, int pos, int sum) {
        if (pos >= n + n) {
            if (sum == 0) return 0;
            return -inf;
        }
        if (dp[last][pos][sum] != -1) return dp[last][pos][sum];
        long ans = 0, a = 0, b = 0, rem = n + n - pos;
        if (rem >= sum + 1) a = max(0, solve(0, pos + 1, sum + 1));
        if (sum - 1 >= 0) b = max(0, solve(0, pos + 1, sum - 1));
        ans = max(ans, a + b);
        if (last == 0) {
            a = 0;
            b = 0;
            if (rem >= sum + 1) a = max(0, solve(1, pos + 1, sum + 1));
            if (sum - 1 >= 0) b = max(0, solve(1, pos + 1, sum - 1));
            ans = max(ans, 1 + a + b);
        }
        if (ans >= 0) ans %= mod;
        return dp[last][pos][sum] = ans;
    }

    static void debug(Object... obj) {
        System.err.println(Arrays.deepToString(obj));
    }
}


import java.util.Scanner;

public class Main {
    static long dp[] = new long[1010];
    static int mod = (int)1e9 + 7;
    static long add(long x, long y){
        long tmp = x + y;
        return tmp >= mod ? tmp - mod : tmp;
    }
    public static void main(String args[]){
        Scanner cin = new Scanner(System.in);
        int n = cin.nextInt();
        dp[0] = 1;
        long ans = 0;
        for(int i = 0; i <= n; i++){
            for(int j = i; j <= n; j++){
                if((i + j) % 2 == 1){
                    ans = add(ans, dp[j]);
                }
                dp[j + 1] = add(dp[j + 1], dp[j]);
            }
        }
        System.out.println(ans);
    }
}


// Change Of Plans BABY.... Change Of Plans //
import java.io.*;
import java.util.*;
import static java.lang.Math.*;

public class nekoAndAkkiPrank {

    static void MainSolution() {
        //constructing tree upside down
        n=2*ni();
        long dp[][]=new long[n+1][n+1];
        boolean free[][]=new boolean[n+1][n+1];
        free[0][0]=true;  // selecting the first edge

        for(int i=1;i<=n;i++){
            for(int j=0;j<=n;j++){
                long l=j-1>=0?dp[i-1][j-1]:0;
                long r=i-1>=j+1?dp[i-1][j+1]:0;

                boolean free_l=j-1>=0?free[i-1][j-1]:false;
                boolean free_r=i-1>=j+1?free[i-1][j+1]:false;

                if(free_l || free_r){
                    dp[i][j]=(l+r+1)%mod9;
                }
                else{
                    dp[i][j] = (l+r)%mod9;
                    free[i][j]=true;
                }
            }
        }
        pl(dp[n][0]);
    }
    /*----------------------------------------------------------------------------------------------------------------*/
    //THE DON'T CARE ZONE BEGINS HERE...\\
    static int mod9 = 1000000007;
    static int n, m, l, k, t, mod = 998244353;
    static AwesomeInput input = new AwesomeInput(System.in);
    static PrintWriter pw = new PrintWriter(System.out, true);

    static class AwesomeInput {
        private InputStream letsDoIT;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private SpaceCharFilter filter;

        private AwesomeInput(InputStream incoming) {
            this.letsDoIT = incoming;
        }

        public int read() {
            if (numChars == -1)
                throw new InputMismatchException();
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = letsDoIT.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0)
                    return -1;
            }
            return buf[curChar++];
        }

        private long ForLong() {
            int c = read();
            while (isSpaceChar(c))
                c = read();
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            long res = 0;
            do {
                if (c < '0' || c > '9')
                    throw new InputMismatchException();
                res *= 10;
                res += c - '0';
                c = read();
            }
            while (!isSpaceChar(c));
            return res * sgn;
        }

        private String ForString() {
            int c = read();
            while (isSpaceChar(c))
                c = read();
            StringBuilder res = new StringBuilder();
            do {
                res.appendCodePoint(c);
                c = read();
            }
            while (!isSpaceChar(c));

            return res.toString();
        }

        public boolean isSpaceChar(int c) {
            if (filter != null)
                return filter.isSpaceChar(c);
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            boolean isSpaceChar(int ch);
        }
    }

    // functions to take input//
    static int ni() {
        return (int) input.ForLong();
    }

    static String ns() {
        return input.ForString();
    }

    static long nl() {
        return input.ForLong();
    }

    static double nd() throws IOException {
        return Double.parseDouble(new BufferedReader(new InputStreamReader(System.in)).readLine());
    }

    //functions to give output
    static void pl() {
        pw.println();
    }

    static void p(Object o) {
        pw.print(o + " ");
    }

    static void pws(Object o) {
        pw.print(o + "");
    }

    static void pl(Object o) {
        pw.println(o);
    }

    public static int[] fastSort(int[] f) {
        int n = f.length;
        int[] to = new int[n];
        {
            int[] b = new int[65537];
            for (int i = 0; i < n; i++) b[1 + (f[i] & 0xffff)]++;
            for (int i = 1; i <= 65536; i++) b[i] += b[i - 1];
            for (int i = 0; i < n; i++) to[b[f[i] & 0xffff]++] = f[i];
            int[] d = f;
            f = to;
            to = d;
        }
        {
            int[] b = new int[65537];
            for (int i = 0; i < n; i++) b[1 + (f[i] >>> 16)]++;
            for (int i = 1; i <= 65536; i++) b[i] += b[i - 1];
            for (int i = 0; i < n; i++) to[b[f[i] >>> 16]++] = f[i];
            int[] d = f;
            f = to;
            to = d;
        }
        return f;
    }

    public static void main(String[] args) {      //threading has been used to increase the stack size.

        new Thread(null, null, "Vengeance", 1 << 25)  //the last parameter is stack size desired.
        {
            public void run() {
                try {
                    double s = System.currentTimeMillis();
                    MainSolution();
                    //pl(("\nExecution Time : " + ((double) System.currentTimeMillis() - s) / 1000) + " s");
                    pw.flush();
                    pw.close();
                } catch (Exception e) {
                    e.printStackTrace();
                    System.exit(1);
                }
            }
        }.start();
    }
}


import java.io.*;
import java.nio.CharBuffer;
import java.util.NoSuchElementException;

public class P1152D {

    public static void main(String[] args) {
        SimpleScanner scanner = new SimpleScanner(System.in);
        PrintWriter writer = new PrintWriter(System.out);

        final int MODULO = 1000000007;
        int n = scanner.nextInt();
        int m = 2 * n;
        int[][] f = new int[m + 1][m + 2];
        f[0][0] = 1;
        int ans = 0;
        for (int i = 1; i <= m; ++i) {
            f[i][0] = f[i - 1][1];
            for (int j = 1; j <= m; ++j) {
                f[i][j] = (f[i - 1][j - 1] + f[i - 1][j + 1]) % MODULO;
            }
            if (i % 2 == 1) {
                for (int j = 1; i + j <= m; j += 2)
                    ans = (ans + f[i][j]) % MODULO;
            }
        }
        writer.println(ans);

        writer.close();
    }

    private static class SimpleScanner {

        private static final int BUFFER_SIZE = 10240;

        private Readable in;
        private CharBuffer buffer;
        private boolean eof;

        SimpleScanner(InputStream in) {
            this.in = new BufferedReader(new InputStreamReader(in));
            buffer = CharBuffer.allocate(BUFFER_SIZE);
            buffer.limit(0);
            eof = false;
        }

        private char read() {
            if (!buffer.hasRemaining()) {
                buffer.clear();
                int n;
                try {
                    n = in.read(buffer);
                } catch (IOException e) {
                    n = -1;
                }
                if (n <= 0) {
                    eof = true;
                    return '\0';
                }
                buffer.flip();
            }
            return buffer.get();
        }

        void checkEof() {
            if (eof)
                throw new NoSuchElementException();
        }

        char nextChar() {
            checkEof();
            char b = read();
            checkEof();
            return b;
        }

        String next() {
            char b;
            do {
                b = read();
                checkEof();
            } while (Character.isWhitespace(b));
            StringBuilder sb = new StringBuilder();
            do {
                sb.append(b);
                b = read();
            } while (!eof && !Character.isWhitespace(b));
            return sb.toString();
        }

        int nextInt() {
            return Integer.valueOf(next());
        }

        long nextLong() {
            return Long.valueOf(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }
    }
}


import java.io.*;
import java.util.*;

public class Task {

    public static void main(String[] args) throws IOException {

        new Task().go();
    }

    PrintWriter out;
    Reader in;
    BufferedReader br;

    Task() throws IOException {

        try {

            //br = new BufferedReader( new FileReader("input.txt") );
            in = new Reader("input.txt");
            out = new PrintWriter( new BufferedWriter(new FileWriter("output.txt")) );
        }
        catch (Exception e) {

            //br = new BufferedReader( new InputStreamReader( System.in ) );
            in = new Reader();
            out = new PrintWriter( new BufferedWriter(new OutputStreamWriter(System.out)) );
        }
    }

    void go() throws IOException {

        int t = 1;
        while (t > 0) {
            solve();
            //out.println();
            t--;
        }

        out.flush();
        out.close();
    }

    int inf = 2000000000;
    int mod = 1000000007;
    double eps = 0.000000001;

    int n;
    int m;
    ArrayList<Integer>[] g;
    void solve() throws IOException {

        int n = in.nextInt();
        int[][] dp = new int[n * 2][n + 1];
        dp[0][1] = 1;
        for (int i = 1; i < n * 2; i++)
            for (int j = 0; j <= n; j++) {
                if (j + 1 <= n) {
                    dp[i][j + 1] += dp[i - 1][j];
                    dp[i][j + 1] %= mod;
                }

                if (j - 1 >= 0) {
                    dp[i][j - 1] += dp[i - 1][j];
                    dp[i][j - 1] %= mod;
                }
            }

        //System.err.println(dp[2 * n - 1][0]);

        int ans = 0;
        for (int i = 2 * n - 2; i >= 0; i -= 2)
            for (int j = 0; j <= n; j++)
                if (j <= 2 * n - 1 - i && j % 2 == 1) {
                    ans = (ans + dp[i][j]) % mod;
                    //System.err.println(i +" " + j + " " + ans);
                }

        out.print(ans);
    }

    class Pair implements Comparable<Pair> {
        int a;
        int b;

        Pair(int a, int b) {
            this.a = a;
            this.b = b;
        }

        public int compareTo(Pair p) {
            if (a != p.a)
                return Integer.compare(a, p.a);
            else
                return Integer.compare(b, p.b);
        }
    }

    class Item {

        int a;
        int b;
        int c;

        Item(int a, int b, int c) {
            this.a = a;
            this.b = b;
            this.c = c;
        }

    }

    class Reader {

        BufferedReader  br;
        StringTokenizer tok;

        Reader(String file) throws IOException {
            br = new BufferedReader( new FileReader(file) );
        }

        Reader() throws IOException {
            br = new BufferedReader( new InputStreamReader(System.in) );
        }

        String next() throws IOException {

            while (tok == null || !tok.hasMoreElements())
                tok = new StringTokenizer(br.readLine());
            return tok.nextToken();
        }

        int nextInt() throws NumberFormatException, IOException {
            return Integer.valueOf(next());
        }

        long nextLong() throws NumberFormatException, IOException {
            return Long.valueOf(next());
        }

        double nextDouble() throws NumberFormatException, IOException {
            return Double.valueOf(next());
        }

        String nextLine() throws IOException {
            return br.readLine();
        }

        int[] nextIntArray(int n) throws IOException {
            int[] a = new int[n];
            for (int i = 0; i < n; i++)
                a[i] = nextInt();
            return a;
        }

        ArrayList<Integer>[] nextGraph(int n, int m) throws IOException {
            ArrayList<Integer>[] g = new ArrayList[n];
            for (int i = 0; i < n; i++)
                g[i] = new ArrayList<>();
            for (int i = 0; i < m; i++) {
                int x = nextInt() - 1;
                int y = nextInt() - 1;
                g[x].add(y);
                g[y].add(x);
            }

            return g;
        }

    }

}


import java.util.*;

import java.io.*;

public class temppp {

	public static void main(String[] args) {

		// TODO Auto-generated method stub

		FastInputReader s = new FastInputReader();
		int n = s.nextInt();
		String str = s.nextLine();
		for(int i=2;i<=n;i++) {
			if(n%i==0) {
				StringBuilder ss = new StringBuilder(str.substring(0,i));
				ss.reverse().toString();
				str=ss.toString()+str.substring(i);

			}
		}
		System.out.println(str);

	}

	public static class FastInputReader {

		private byte[] buf = new byte[16384];

		private int curChar;

		private int numChars;

		public int read() {

			if (numChars == -1)

				throw new InputMismatchException();

			if (curChar >= numChars) {

				curChar = 0;

				try {

					numChars = System.in.read(buf);

				} catch (IOException e) {

					throw new InputMismatchException();

				}

				if (numChars <= 0)

					return -1;

			}

			return buf[curChar++];

		}

		public String nextLine() {

			int c = read();

			while (isSpaceChar(c))

				c = read();

			StringBuilder res = new StringBuilder();

			do {

				res.appendCodePoint(c);

				c = read();

			} while (!isEndOfLine(c));

			return res.toString();

		}

		public String nextString() {

			int c = read();

			while (isSpaceChar(c))

				c = read();

			StringBuilder res = new StringBuilder();

			do {

				res.appendCodePoint(c);

				c = read();

			} while (!isSpaceChar(c));

			return res.toString();

		}

		public long nextLong() {

			int c = read();

			while (isSpaceChar(c))

				c = read();

			int sgn = 1;

			if (c == '-') {

				sgn = -1;

				c = read();

			}

			long res = 0;

			do {

				if (c < '0' || c > '9')

					throw new InputMismatchException();

				res *= 10;

				res += c - '0';

				c = read();

			} while (!isSpaceChar(c));

			return res * sgn;

		}

		public int nextInt() {

			int c = read();

			while (isSpaceChar(c))

				c = read();

			int sgn = 1;

			if (c == '-') {

				sgn = -1;

				c = read();

			}

			int res = 0;

			do {

				if (c < '0' || c > '9')

					throw new InputMismatchException();

				res *= 10;

				res += c - '0';

				c = read();

			} while (!isSpaceChar(c));

			return res * sgn;

		}

		public int[] nextIntArray(int n) {

			int[] arr = new int[n];

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

				arr[i] = nextInt();

			}

			return arr;

		}

		public long[] nextLongArray(int n) {

			long[] arr = new long[n];

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

				arr[i] = nextLong();

			}

			return arr;

		}

		private boolean isSpaceChar(int c) {

			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;

		}

		private boolean isEndOfLine(int c) {

			return c == '\n' || c == '\r' || c == -1;

		}

	}

	public static class MyScanner {

		BufferedReader reader;

		public MyScanner() {

			this.reader = new BufferedReader(new InputStreamReader(System.in));

		}

		public void close() throws IOException {

			this.reader.close();

		}

		int nextInt() {

			return Integer.parseInt(this.next());

		}

		long nextLong() {

			return Long.parseLong(this.next());

		}

		float nextFloat() {

			return Float.parseFloat(this.next());

		}

		double nextDouble() {

			return Double.parseDouble(this.next());

		}

		String next() {

			String str = "";

			try {

				str = this.reader.readLine().trim();

			} catch (IOException e) {

				e.printStackTrace();

			}

			return str;

		}

		String[] nextStringArray() {

			String[] str = null;

			try {

				str = this.reader.readLine().trim().split(" ");

			} catch (IOException e) {

				e.printStackTrace();

			}

			return str;

		}

		int[] nextIntArray() {

			String[] data = nextStringArray();

			int[] a = new int[data.length];

			for (int i = 0; i < a.length; i++) {

				a[i] = Integer.parseInt(data[i]);

			}

			return a;

		}

		Integer[] nextIntegerArray() {

			String[] data = nextStringArray();

			Integer[] a = new Integer[data.length];

			for (int i = 0; i < a.length; i++) {

				a[i] = Integer.parseInt(data[i]);

			}

			return a;

		}

		long[] nextLongArray() {

			String[] data = nextStringArray();

			long[] a = new long[data.length];

			for (int i = 0; i < a.length; i++) {

				a[i] = Long.parseLong(data[i]);

			}

			return a;

		}

		float[] nextFloatArray() {

			String[] data = nextStringArray();

			float[] a = new float[data.length];

			for (int i = 0; i < a.length; i++) {

				a[i] = Float.parseFloat(data[i]);

			}

			return a;

		}

		double[] nextDoubleArray() {

			String[] data = nextStringArray();

			double[] a = new double[data.length];

			for (int i = 0; i < a.length; i++) {

				a[i] = Double.parseDouble(data[i]);

			}

			return a;

		}

	}

}


import java.util.*;

public class Main
{

	public static void main(String[] args)
	{

		Scanner sc = new Scanner(System.in);
		long l = sc.nextInt();
		long r = sc.nextInt();
		long x = sc.nextInt();
		long y = sc.nextInt();

		long k = sc.nextInt();

		long min = k*y - l;
		long max = r - k*x;

		if(min>=0 && max>=0)
		{
			boolean check = false;

			for(long i=x;i<=y && k*i<=r && !check;i++)
			{
				if(k*i<=r && k*i>=l)
					check = true;
			}

			if(check)
				System.out.println("YES");
			else
				System.out.println("NO");
		}
		else
			System.out.println("NO");
	}
}


import java.io.*;
import java.util.*;

public class C {

	BufferedReader br;
	PrintWriter out;
	StringTokenizer st;
	boolean eof;

	int n, m;

	class Edge {
		int to, flow, cap, cost;
		Edge rev;

		public Edge(int to, int cap, int cost) {
			this.to = to;
			this.cap = cap;
			this.cost = cost;
		}
	}

	static final int[] dx = { -1, 0, 1, 0 };
	static final int[] dy = { 0, -1, 0, 1 };
	static final int INF = Integer.MAX_VALUE / 3;

	List<Edge>[] g;

	void addEdge(int v1, int v2, int cost) {
		Edge e1 = new Edge(v2, 1, cost);
		Edge e2 = new Edge(v1, 0, -cost);
		e1.rev = e2;
		e2.rev = e1;
		g[v1].add(e1);
		g[v2].add(e2);
	}

	int S, T;

	void solve() throws IOException {
		n = nextInt();
		m = nextInt();

		int[][] f = new int[n][m];
		for (int i = 0; i < n; i++)
			for (int j = 0; j < m; j++)
				f[i][j] = nextInt();

		g = new ArrayList[n * m + 2];
		S = n * m;
		T = n * m + 1;
		for (int i = 0; i < n * m; i++)
			g[i] = new ArrayList<>(5);
		g[S] = new ArrayList<>(n * m / 2);
		g[T] = new ArrayList<>(n * m / 2);

		for (int i = 0; i < n; i++)
			for (int j = 0; j < m; j++) {
				int v = i * m + j;
				int col = (i + j) & 1;
				if (col == 0) {
					addEdge(S, v, 0);
					for (int dir = 0; dir < 4; dir++) {
						int ni = i + dx[dir];
						int nj = j + dy[dir];
						if (ni >= 0 && ni < n && nj >= 0 && nj < m) {
							int to = ni * m + nj;
							int cost = (f[i][j] == f[ni][nj] ? 0 : 1);
							addEdge(v, to, cost);
						}
					}
				} else {
					addEdge(v, T, 0);
				}
			}

		int ans = 0;
		int[] pi = new int[n * m + 2];

		final int[] d = new int[n * m + 2];
		Edge[] from = new Edge[n * m + 2];

		Integer[] Integers = new Integer[n * m + 2];
		for (int i = 0; i < n * m + 2; i++)
			Integers[i] = i;

		TreeSet<Integer> set = new TreeSet<>(new Comparator<Integer>() {

			@Override
			public int compare(Integer o1, Integer o2) {
				if (d[o1] != d[o2])
					return Integer.compare(d[o1], d[o2]);
				return o1.compareTo(o2);
			}

		});

		for (int iter = 0; iter < n * m / 2; iter++) {

			Arrays.fill(d, INF);
			d[S] = 0;

			set.add(Integers[S]);

			while (!set.isEmpty()) {
				int v = set.pollFirst();

				for (int i = 0; i < g[v].size(); i++) {
					Edge e = g[v].get(i);
					if (e.flow < e.cap) {
						int redCost = e.cost - pi[v] + pi[e.to];
						if (redCost < 0)
							throw new AssertionError();
						if (d[e.to] > d[v] + redCost) {
							set.remove(Integers[e.to]);
							from[e.to] = e;
							d[e.to] = d[v] + redCost;
							set.add(Integers[e.to]);
						}
					}
				}
			}

			for (int i = 0; i < n * m + 2; i++) {
				pi[i] -= d[i];
			}

			for (int v = T; v != S; ) {
				Edge last = from[v];
				last.flow++;
				last.rev.flow--;
				ans += last.cost;
				v = last.rev.to;
			}

		}

		out.println(ans);

	}

	C() throws IOException {
		br = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		solve();
		out.close();
	}

	public static void main(String[] args) throws IOException {
		new C();
	}

	String nextToken() {
		while (st == null || !st.hasMoreTokens()) {
			try {
				st = new StringTokenizer(br.readLine());
			} catch (Exception e) {
				eof = true;
				return null;
			}
		}
		return st.nextToken();
	}

	String nextString() {
		try {
			return br.readLine();
		} catch (IOException e) {
			eof = true;
			return null;
		}
	}

	int nextInt() throws IOException {
		return Integer.parseInt(nextToken());
	}

	long nextLong() throws IOException {
		return Long.parseLong(nextToken());
	}

	double nextDouble() throws IOException {
		return Double.parseDouble(nextToken());
	}
}


import java.util.Comparator;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.List;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.ArrayList;
import java.util.ArrayDeque;
import java.io.Reader;
import java.util.TreeSet;
import java.util.Collections;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 * @author Niyaz Nigmatullin
 */
public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		FastScanner in = new FastScanner(inputStream);
		FastPrinter out = new FastPrinter(outputStream);
		TaskC2 solver = new TaskC2();
		solver.solve(1, in, out);
		out.close();
	}
}

class TaskC2 {

    final int[] DX = {1, 0, -1, 0};
    final int[] DY = {0, 1, 0, -1};

    public void solve(int testNumber, FastScanner in, FastPrinter out) {
        int n = in.nextInt();
        int m = in.nextInt();
        int[][] a = new int[n][];
        for (int i = 0; i < n; i++) {
            a[i] = in.readIntArray(m);
        }
        boolean[][] has = new boolean[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                for (int dir = 0; dir < 4; dir++) {
                    int x = i + DX[dir];
                    int y = j + DY[dir];
                    if (x < 0 || y < 0 || x >= n || y >= m || a[x][y] != a[i][j]) continue;
                    has[i][j] = true;
                }
            }
        }
        MinCostMaxFlowGraph g = new MinCostMaxFlowGraph(n * m + 2);
        int source = n * m;
        int target = n * m + 1;
        int ans = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (has[i][j]) {
                    continue;
                }
                if ((i + j & 1) == 1) {
                    g.addEdge(i * m + j, target, 0, 1, 0);
                    continue;
                }
                g.addEdge(source, i * m + j, 0, 1, 0);
                ans++;
                ArrayDeque<Integer> q = new ArrayDeque<>();
                int[][] d = new int[n][m];
                for (int[] e : d) {
                    Arrays.fill(e, Integer.MAX_VALUE);
                }
                d[i][j] = 0;
                q.add(i * m + j);
                while (!q.isEmpty()) {
                    int v = q.pollFirst();
                    int cx = v / m;
                    int cy = v % m;
                    for (int dir = 0; dir < 4; dir++) {
                        int x = cx + DX[dir];
                        int y = cy + DY[dir];
                        if (x < 0 || y < 0 || x >= n || y >= m) continue;
                        int cost = 1;
                        if (a[x][y] == a[cx][cy]) cost = 0;
                        if (d[x][y] > d[cx][cy] + cost) {
                            q.addLast(x * m + y);
                            d[x][y] = d[cx][cy] + cost;
                        }
                    }
                }
                for (int x = 0; x < n; x++) {
                    for (int y = 0; y < m; y++) {
                        if ((x + y & 1) == 0) continue;
                        if (has[x][y]) continue;
                        g.addEdge(i * m + j, x * m + y, 0, 1, d[x][y] - 1);
                    }
                }
            }
        }
//        System.out.println(ans);
        ans += g.getMinCostMaxFlow(source, target)[1];
        out.println(ans);
    }

    }

class FastScanner extends BufferedReader {

    public FastScanner(InputStream is) {
        super(new InputStreamReader(is));
    }

    public int read() {
        try {
            int ret = super.read();
//            if (isEOF && ret < 0) {
//                throw new InputMismatchException();
//            }
//            isEOF = ret == -1;
            return ret;
        } catch (IOException e) {
            throw new InputMismatchException();
        }
    }

    static boolean isWhiteSpace(int c) {
        return c >= 0 && c <= 32;
    }

    public int nextInt() {
        int c = read();
        while (isWhiteSpace(c)) {
            c = read();
        }
        int sgn = 1;
        if (c == '-') {
            sgn = -1;
            c = read();
        }
        int ret = 0;
        while (c >= 0 && !isWhiteSpace(c)) {
            if (c < '0' || c > '9') {
                throw new NumberFormatException("digit expected " + (char) c
                        + " found");
            }
            ret = ret * 10 + c - '0';
            c = read();
        }
        return ret * sgn;
    }

    public String readLine() {
        try {
            return super.readLine();
        } catch (IOException e) {
            return null;
        }
    }

    public int[] readIntArray(int n) {
        int[] ret = new int[n];
        for (int i = 0; i < n; i++) {
            ret[i] = nextInt();
        }
        return ret;
    }

    }

class FastPrinter extends PrintWriter {

    public FastPrinter(OutputStream out) {
        super(out);
    }

    public FastPrinter(Writer out) {
        super(out);
    }

}

class MinCostMaxFlowGraph {
    public static class Edge {
        int from;
        int to;
        public int flow;
        int cap;
        long cost;
        Edge rev;

        public Edge(int from, int to, int flow, int cap, long cost) {
            this.from = from;
            this.to = to;
            this.flow = flow;
            this.cap = cap;
            this.cost = cost;
        }

        public String toString() {
            return "Edge [from=" + from + ", to=" + to + ", flow=" + flow
                    + ", cap=" + cap + ", cost=" + cost + "]";
        }

    }

    int n;
    ArrayList<Edge>[] edges;

    public MinCostMaxFlowGraph(int n) {
        this.n = n;
        edges = new ArrayList[n];
        for (int i = 0; i < edges.length; i++) {
            edges[i] = new ArrayList<Edge>();
        }
    }

    public Edge addEdge(int from, int to, int flow, int cap, long cost) {
        Edge e1 = new Edge(from, to, flow, cap, cost);
        Edge e2 = new Edge(to, from, flow, 0, -cost);
        e1.rev = e2;
        e2.rev = e1;
        edges[from].add(e1);
        edges[to].add(e2);
        return e1;
    }

    public long[] getMinCostMaxFlow(int source, int target) {
        long[] h = new long[n];
        for (boolean changed = true; changed; ) {
            changed = false;
            for (int i = 0; i < n; i++) {
                for (Edge e : edges[i]) {
                    if (e.cap > 0 && h[e.to] > h[e.from] + e.cost) {
                        h[e.to] = h[e.from] + e.cost;
                        changed = true;
                    }
                }
            }
        }
        Edge[] lastEdge = new Edge[n];
        long[] d = new long[n];
        int flow = 0;
        long cost = 0;
        while (true) {
            dijkstra(source, lastEdge, d, h);
            if (d[target] == Long.MAX_VALUE) {
                break;
            }
            int addFlow = Integer.MAX_VALUE;
            for (int v = target; v != source; ) {
                Edge e = lastEdge[v];
                addFlow = Math.min(addFlow, e.cap - e.flow);
                v = e.from;
            }
            cost += (d[target] + h[target] - h[source]) * addFlow;
            flow += addFlow;
            for (int v = target; v != source; ) {
                Edge e = lastEdge[v];
                e.flow += addFlow;
                e.rev.flow -= addFlow;
                v = e.from;
            }
            for (int i = 0; i < n; i++) {
                h[i] += d[i] == Long.MAX_VALUE ? 0 : d[i];
            }
        }
        return new long[]{flow, cost};
    }

    void dijkstra(int source, Edge[] lastEdge, final long[] d, long[] h) {
        TreeSet<Integer> ts = new TreeSet<Integer>(new Comparator<Integer>() {
            public int compare(Integer o1, Integer o2) {
                if (d[o1] != d[o2]) {
                    return d[o1] < d[o2] ? -1 : 1;
                }
                return o1 - o2;
            }
        });
        Arrays.fill(d, Long.MAX_VALUE);
        d[source] = 0;
        ts.add(source);
        while (!ts.isEmpty()) {
            int v = ts.pollFirst();
            for (Edge e : edges[v]) {
                if (e.flow >= e.cap) {
                    continue;
                }
                if (d[e.to] == Long.MAX_VALUE
                        || d[e.to] > d[e.from] + e.cost + h[e.from]
                        - h[e.to]) {
                    if (e.cost + h[e.from] - h[e.to] < 0) {
                        throw new AssertionError();
                    }
                    ts.remove(e.to);
                    d[e.to] = d[e.from] + e.cost + h[e.from] - h[e.to];
                    lastEdge[e.to] = e;
                    ts.add(e.to);
                }
            }
        }
    }
}


import java.io.*;
import java.util.*;
import java.math.*;
import java.awt.geom.*;

import static java.lang.Math.*;

public class Solution implements Runnable {

	class Edge {
		int from, to, u, f, c;

		public Edge(int from, int to, int u, int c) {
			this.from = from;
			this.to = to;
			this.u = u;
			this.c = c;
		}
	}

	int dr [] = new int [] {0, 0, 1, -1};
	int dc [] = new int [] {1, -1, 0, 0};

	int N, S, T;
	ArrayList<Edge> edges;
	ArrayList<Integer> g[];
	int [] d, pv, pe;
	boolean [] inQueue;

	void addEdge (int from, int to, int u, int c) {
		g[from].add(edges.size());
		edges.add(new Edge (from, to, u, c));
		g[to].add(edges.size());
		edges.add(new Edge (to, from, 0, -c));
	}

	int minCostMaxFlow () {
		int result = 0;

		d = new int [N];
		inQueue = new boolean [N];
		pe = new int [N];
		pv = new int [N];
		Queue<Integer> q = new ArrayDeque<>();

		while (true) {
			Arrays.fill(inQueue, false);
			Arrays.fill(d, Integer.MAX_VALUE / 2);
			d[S] = 0;
			inQueue[S] = true;
			q.add(S);
			while (!q.isEmpty()) {
				int v = q.poll();
				inQueue[v] = false;
				for (int i = 0; i < g[v].size(); i++) {
					int index = g[v].get(i);
					Edge e = edges.get(index);
					if (e.u > e.f) {
						if (d[e.to] > d[v] + e.c) {
							d[e.to] = d[v] + e.c;
							pv[e.to] = v;
							pe[e.to] = index;
							if (!inQueue[e.to]) {
								inQueue[e.to] = true;
								q.add(e.to);
							}
						}
					}
				}
			}
			if (d[T] == Integer.MAX_VALUE / 2) break;
			int addFlow = Integer.MAX_VALUE / 2;
			for (int v = T; v != S; v = pv[v]) {
				int index = pe[v];
				Edge e = edges.get(index);
				addFlow = min (addFlow, e.u - e.f);
			}
			for (int v = T; v != S; v = pv[v]) {
				int index = pe[v];
				Edge dir = edges.get(index);
				Edge rev = edges.get(index ^ 1);
				result += addFlow * dir.c;
				dir.f += addFlow;
				rev.f -= addFlow;
			}
		}
		return result;
	}

	public void solve() throws Exception {
		int n = sc.nextInt();
		int m = sc.nextInt();

		int a [][] = new int [n][m];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				a[i][j] = sc.nextInt();
			}
		}

		N = n * m + 2;
		S = n * m;
		T = n * m + 1;

		edges = new ArrayList<>();

		g = new ArrayList[N];
		for (int i = 0; i < N; i++)
			g[i] = new ArrayList<>();

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if ((i + j) % 2 == 0) {
					addEdge(S, i * m + j, 1, 0);
					for (int k = 0; k < 4; k++) {
						int di = dr[k] + i;
						int dj = dc[k] + j;
						if (di >= 0 && dj >= 0 && di < n && dj < m) {
							int cost = 1;
							if (a[i][j] == a[di][dj]) cost = 0;
							addEdge(i * m + j, di * m + dj, 1, cost);
						}
					}
				} else {
					addEdge(i * m + j, T, 1, 0);
				}
			}
		}
		out.println(minCostMaxFlow());
	}

	BufferedReader in;
	PrintWriter out;
	FastScanner sc;

	static Throwable uncaught;

	@Override
	public void run() {
		try {
			in = new BufferedReader(new InputStreamReader(System.in));
			out = new PrintWriter(System.out);
			sc = new FastScanner(in);
			solve();
		} catch (Throwable t) {
			Solution.uncaught = t;
		} finally {
			out.close();
		}
	}

	public static void main(String[] args) throws Throwable {
		Thread t = new Thread(null, new Solution(), "", (1 << 26));
		t.start();
		t.join();
		if (uncaught != null) {
			throw uncaught;
		}
	}

}

class FastScanner {

	BufferedReader reader;
	StringTokenizer strTok;

	public FastScanner(BufferedReader reader) {
		this.reader = reader;
	}

	public String nextToken() throws IOException {
		while (strTok == null || !strTok.hasMoreTokens()) {
			strTok = new StringTokenizer(reader.readLine());
		}
		return strTok.nextToken();
	}

	public int nextInt() throws IOException {
		return Integer.parseInt(nextToken());
	}

	public long nextLong() throws IOException {
		return Long.parseLong(nextToken());
	}

	public double nextDouble() throws IOException {
		return Double.parseDouble(nextToken());
	}

}


import java.util.*;

public class C {
	private static Scanner in;

	public static final int[] dx = new int[]{1, 0, -1, 0};
	public static final int[] dy = new int[]{0, 1, 0, -1};

	public void run() {
		int hei = in.nextInt();
		int wid = in.nextInt();
		int s = hei * wid / 2;
		int[][] a = new int[hei][wid];
		for (int i = 0; i < hei; i++) {
			for (int j = 0; j < wid; j++) {
				a[i][j] = in.nextInt() - 1;
			}
		}
		int infty = 3 * s;
		int[][] e = new int[s][s];
		for (int i = 0; i < s; i++) {
			Arrays.fill(e[i], infty);
		}
		for (int i = 0; i < hei; i++) {
			for (int j = 0; j < wid; j++) {
				if ((i + j) % 2 == 0) {
					continue;
				}
				int x = (i * wid + j) / 2;
				for (int d = 0; d < 4; d++) {
					int ii = i + dx[d];
					int jj = j + dy[d];
					if (ii < 0 || jj < 0 || ii >= hei || jj >= wid) {
						continue;
					}
					int y = (ii * wid + jj) / 2;
					e[x][y] = (a[i][j] == a[ii][jj]) ? 0 : 1;
				}
			}
		}
		System.out.println(hungarian(e));
	}

	public static void main(String[] args) {
		Locale.setDefault(Locale.US);
		in = new Scanner(System.in);
		new C().run();
		in.close();
	}

	/*
	 * infty must be greater than all elements of e
	 */
	public static int hungarian(int[][] e) {
		int infty = Integer.MAX_VALUE / 3;
		int n1 = e.length;
		int n2 = e[0].length;
		int[] u = new int[n1 + 1];
		int[] v = new int[n2 + 1];
		int[] p = new int[n2 + 1];
		int[] way = new int[n2 + 1];
		for (int i = 1; i <= n1; i++) {
			p[0] = i;
			int j0 = 0;
			int[] minv = new int[n2 + 1];
			Arrays.fill(minv, infty);
			boolean[] used = new boolean[n2 + 1];
			do {
				used[j0] = true;
				int i0 = p[j0], j1 = 0;
				double delta = infty;
				for (int j = 1; j <= n2; j++) {
					if (!used[j]) {
						int cur = e[i0 - 1][j - 1] - u[i0] - v[j];
						if (cur < minv[j]) {
							minv[j] = cur;
							way[j] = j0;
						}
						if (minv[j] < delta) {
							delta = minv[j];
							j1 = j;
						}
					}
				}
				for (int j = 0; j <= n2; j++) {
					if (used[j]) {
						u[p[j]] += delta;
						v[j] -= delta;
					} else {
						minv[j] -= delta;
					}
				}
				j0 = j1;
			} while (p[j0] != 0);
			do {
				int j1 = way[j0];
				p[j0] = p[j1];
				j0 = j1;
			} while (j0 > 0);
		}
		int sum = 0;
		for (int j = 1; j <= n2; j++) {
			if (p[j] > 0) {
				// if (e[p[j] - 1][j - 1] >= infty) no matching of size n1;
				sum += e[p[j] - 1][j - 1];
			}
		}
		return sum;
	}
}


import java.util.*;
import java.io.*;
import java.io.File;
import java.util.AbstractSet;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.math.*;
public class Hello {

  //static FastReader in = new FastReader(System.in);
  public static void main(String[] args) {
    //try {
    //  FileInputStream fis = new FileInputStream("data.txt");
    //  System.setIn(fis);
      Scanner in = new Scanner(System.in);
      // Scanner in = new Scanner(new File("input.txt"));
      // PrintWriter out = new PrintWriter("output.txt");

      int n = in.nextInt();
      int m = in.nextInt();

      int [][]a = new int[n][m];

      for (int i = 0;i < n;++i) {
	for (int j = 0;j < m;++j) {
	  a[i][j] = in.nextInt() - 1;
	}
      }

      //r * (c - 1);
      //c * (r - 1);

      int shoe = m * n / 2;

      int []dx = {-1, 0, 0, 1};
      int []dy = {0, -1, 1, 0};

      //shoe * (r * (c - 1)+ c * (r - 1)) *

      //List<Edge>[] graph = createGraph(2 * shoe + 2);
      Graph graph = new Graph(2 * shoe + 2);

      int source = 2 * shoe, sink = 2 * shoe + 1;

      for (int i = 0;i < n;++i) {
	for (int j = 0;j < m;++j) {
	  int id = i * m + j;
	  if ((i + j) % 2 == 0) {//left
	    for (int z = 0;z < 4;++z) {
	      int i1 = i + dx[z];
	      int j1 = j + dy[z];
	      if (i1 < 0 || i1 >= n || j1 < 0 || j1 >= m) continue;
	      int id1 = i1 * m + j1;
	      int wt = (a[i][j] == a[i1][j1])?0:1;
	      graph.addFlowWeightedEdge(id, id1, wt, 1);
	    }
	    graph.addFlowWeightedEdge(source, id, 0, 1);
	  } else {//right
	    graph.addFlowWeightedEdge(id, sink, 0, 1);
	  }
	}
      }
      MinCostFlow mcf = new MinCostFlow(graph, source, sink, false);
      Pair<Long, Long> ans = mcf.minCostMaxFlow();
      System.out.println(ans.first);
    //} catch (FileNotFoundException e){
    //  System.out.println("error");
    //}
  }
///////////////////////
}
class Graph {
  public static final int REMOVED_BIT = 0;

  protected int vertexCount;
  protected int edgeCount;

  private int[] firstOutbound;
  private int[] firstInbound;

  private Edge[] edges;
  private int[] nextInbound;
  private int[] nextOutbound;
  private int[] from;
  private int[] to;
  private long[] weight;
  private long[] capacity;
  private int[] reverseEdge;
  private int[] flags;

  public Graph(int vertexCount) {
    this(vertexCount, vertexCount);
  }

  public Graph(int vertexCount, int edgeCapacity) {
    this.vertexCount = vertexCount;
    firstOutbound = new int[vertexCount];
    Arrays.fill(firstOutbound, -1);

    from = new int[edgeCapacity];
    to = new int[edgeCapacity];
    nextOutbound = new int[edgeCapacity];
    flags = new int[edgeCapacity];
  }

  public int addEdge(int fromID, int toID, long weight, long capacity, int reverseEdge) {
    ensureEdgeCapacity(edgeCount + 1);
    if (firstOutbound[fromID] != -1)
      nextOutbound[edgeCount] = firstOutbound[fromID];
    else
      nextOutbound[edgeCount] = -1;
    firstOutbound[fromID] = edgeCount;
    if (firstInbound != null) {
      if (firstInbound[toID] != -1)
	nextInbound[edgeCount] = firstInbound[toID];
      else
	nextInbound[edgeCount] = -1;
      firstInbound[toID] = edgeCount;
    }
    this.from[edgeCount] = fromID;
    this.to[edgeCount] = toID;
    if (capacity != 0) {
      if (this.capacity == null)
	this.capacity = new long[from.length];
      this.capacity[edgeCount] = capacity;
    }
    if (weight != 0) {
      if (this.weight == null)
	this.weight = new long[from.length];
      this.weight[edgeCount] = weight;
    }
    if (reverseEdge != -1) {
      if (this.reverseEdge == null) {
	this.reverseEdge = new int[from.length];
	Arrays.fill(this.reverseEdge, 0, edgeCount, -1);
      }
      this.reverseEdge[edgeCount] = reverseEdge;
    }
    if (edges != null)
      edges[edgeCount] = createEdge(edgeCount);
    return edgeCount++;
  }

  protected final GraphEdge createEdge(int id) {
    return new GraphEdge(id);
  }

  public final int addFlowWeightedEdge(int from, int to, long weight, long capacity) {
    if (capacity == 0) {
      return addEdge(from, to, weight, 0, -1);
    } else {
      int lastEdgeCount = edgeCount;
      addEdge(to, from, -weight, 0, lastEdgeCount + entriesPerEdge());
      return addEdge(from, to, weight, capacity, lastEdgeCount);
    }
  }

  protected int entriesPerEdge() {
    return 1;
  }

  public final int addFlowEdge(int from, int to, long capacity) {
    return addFlowWeightedEdge(from, to, 0, capacity);
  }

  public final int vertexCount() {
    return vertexCount;
  }

  public final int firstOutbound(int vertex) {
    int id = firstOutbound[vertex];
    while (id != -1 && isRemoved(id))
      id = nextOutbound[id];
    return id;
  }

  public final int nextOutbound(int id) {
    id = nextOutbound[id];
    while (id != -1 && isRemoved(id))
      id = nextOutbound[id];
    return id;
  }

  public final int source(int id) {
    return from[id];
  }

  public final int destination(int id) {
    return to[id];
  }

  public final long weight(int id) {
    if (weight == null)
      return 0;
    return weight[id];
  }

  public final long capacity(int id) {
    if (capacity == null)
      return 0;
    return capacity[id];
  }

  public final long flow(int id) {
    if (reverseEdge == null)
      return 0;
    return capacity[reverseEdge[id]];
  }

  public final void pushFlow(int id, long flow) {
    if (flow == 0)
      return;
    if (flow > 0) {
      if (capacity(id) < flow)
	throw new IllegalArgumentException("Not enough capacity");
    } else {
      if (flow(id) < -flow)
	throw new IllegalArgumentException("Not enough capacity");
    }
    capacity[id] -= flow;
    capacity[reverseEdge[id]] += flow;
  }

  public final boolean flag(int id, int bit) {
    return (flags[id] >> bit & 1) != 0;
  }

  public final boolean isRemoved(int id) {
    return flag(id, REMOVED_BIT);
  }

  protected void ensureEdgeCapacity(int size) {
    if (from.length < size) {
      int newSize = Math.max(size, 2 * from.length);
      if (edges != null)
	edges = resize(edges, newSize);
      from = resize(from, newSize);
      to = resize(to, newSize);
      nextOutbound = resize(nextOutbound, newSize);
      if (nextInbound != null)
	nextInbound = resize(nextInbound, newSize);
      if (weight != null)
	weight = resize(weight, newSize);
      if (capacity != null)
	capacity = resize(capacity, newSize);
      if (reverseEdge != null)
	reverseEdge = resize(reverseEdge, newSize);
      flags = resize(flags, newSize);
    }
  }

  protected final int[] resize(int[] array, int size) {
    int[] newArray = new int[size];
    System.arraycopy(array, 0, newArray, 0, array.length);
    return newArray;
  }

  private long[] resize(long[] array, int size) {
    long[] newArray = new long[size];
    System.arraycopy(array, 0, newArray, 0, array.length);
    return newArray;
  }

  private Edge[] resize(Edge[] array, int size) {
    Edge[] newArray = new Edge[size];
    System.arraycopy(array, 0, newArray, 0, array.length);
    return newArray;
  }

  public final boolean isSparse() {
    return vertexCount == 0 || edgeCount * 20 / vertexCount <= vertexCount;
  }

  protected class GraphEdge implements Edge {
    protected int id;

    protected GraphEdge(int id) {
      this.id = id;
    }

  }

}

class MinCostFlow {
  private final Graph graph;
  private final int source;
  private final int destination;
  private final long[] phi;
  private final long[] dijkstraResult;
  private final int[] lastEdge;
  private final Heap heap;
  private final int vertexCount;
  private final int[] visited;
  private int visitIndex;

  public MinCostFlow(Graph graph, int source, int destination, boolean hasNegativeEdges) {
    this.graph = graph;
    this.source = source;
    this.destination = destination;
    vertexCount = graph.vertexCount();
    phi = new long[vertexCount];
    if (hasNegativeEdges)
      fordBellman();
    dijkstraResult = new long[vertexCount];
    lastEdge = new int[vertexCount];
    if (graph.isSparse()) {
      heap = new Heap(vertexCount, new IntComparator() {
	  public int compare(int first, int second) {
	  return IntegerUtils.longCompare(dijkstraResult[first], dijkstraResult[second]);
	  }
	  }, vertexCount);
      visited = null;
    } else {
      heap = null;
      visited = new int[vertexCount];
    }
  }

  private void fordBellman() {
    Arrays.fill(phi, Long.MAX_VALUE);
    phi[source] = 0;
    boolean[] inQueue = new boolean[vertexCount];
    int[] queue = new int[vertexCount + 1];
    queue[0] = source;
    inQueue[source] = true;
    int stepCount = 0;
    int head = 0;
    int end = 1;
    int maxSteps = 2 * vertexCount * vertexCount;
    while (head != end) {
      int vertex = queue[head++];
      if (head == queue.length)
	head = 0;
      inQueue[vertex] = false;
      int edgeID = graph.firstOutbound(vertex);
      while (edgeID != -1) {
	long total = phi[vertex] + graph.weight(edgeID);
	int destination = graph.destination(edgeID);
	if (graph.capacity(edgeID) != 0 && phi[destination] > total) {
	  phi[destination] = total;
	  if (!inQueue[destination]) {
	    queue[end++] = destination;
	    inQueue[destination] = true;
	    if (end == queue.length)
	      end = 0;
	  }
	}
	edgeID = graph.nextOutbound(edgeID);
      }
      if (++stepCount > maxSteps)
	throw new IllegalArgumentException("Graph contains negative cycle");
    }
  }

  class Heap {
    IntList list;
    int shift;
    int[] index;

    public Heap(int vertexCount, IntComparator intComparator, int vertexCount1) {
      list = new IntArrayList(vertexCount);
      index = new int[vertexCount1];
      Arrays.fill(index, -1);
    }

    public void add(int source) {
      index[source] = 0;
      list.add(source);
    }

    public boolean isEmpty() {
      return shift == list.size();
    }

    public int poll() {
      int result = list.get(shift++);
      index[result] = -1;
      return result;
    }

    public int getIndex(int next) {
      return index[next];
    }

    public void shiftUp(int index) {
    }

    public void clear() {
      list = new IntArrayList();
      shift = 0;
      Arrays.fill(index, -1);
    }
  }

  public Pair<Long, Long> minCostMaxFlow() {
    return minCostMaxFlow(Long.MAX_VALUE);
  }

  public Pair<Long, Long> minCostMaxFlow(long maxFlow) {
    long cost = 0;
    long flow = 0;
    while (maxFlow != 0) {
      if (graph.isSparse())
	dijkstraAlgorithm();
      else
	dijkstraAlgorithmFull();
      if (lastEdge[destination] == -1)
	return Pair.makePair(cost, flow);
      for (int i = 0; i < dijkstraResult.length; i++) {
	if (dijkstraResult[i] != Long.MAX_VALUE)
	  phi[i] += dijkstraResult[i];
      }
      int vertex = destination;
      long currentFlow = maxFlow;
      long currentCost = 0;
      while (vertex != source) {
	int edgeID = lastEdge[vertex];
	currentFlow = Math.min(currentFlow, graph.capacity(edgeID));
	currentCost += graph.weight(edgeID);
	vertex = graph.source(edgeID);
      }
      maxFlow -= currentFlow;
      cost += currentCost * currentFlow;
      flow += currentFlow;
      vertex = destination;
      while (vertex != source) {
	int edgeID = lastEdge[vertex];
	graph.pushFlow(edgeID, currentFlow);
	vertex = graph.source(edgeID);
      }
    }
    return Pair.makePair(cost, flow);
  }

  private void dijkstraAlgorithm() {
    Arrays.fill(dijkstraResult, Long.MAX_VALUE);
    Arrays.fill(lastEdge, -1);
    dijkstraResult[source] = 0;
    heap.clear();
    heap.add(source);
    while (!heap.isEmpty()) {
      int current = heap.poll();
      int edgeID = graph.firstOutbound(current);
      while (edgeID != -1) {
	if (graph.capacity(edgeID) != 0) {
	  int next = graph.destination(edgeID);
	  long total = graph.weight(edgeID) - phi[next] + phi[current] + dijkstraResult[current];
	  if (dijkstraResult[next] > total) {
	    dijkstraResult[next] = total;
	    if (heap.getIndex(next) == -1)
	      heap.add(next);
	    else
	      heap.shiftUp(heap.getIndex(next));
	    lastEdge[next] = edgeID;
	  }
	}
	edgeID = graph.nextOutbound(edgeID);
      }
    }
  }

  private void dijkstraAlgorithmFull() {
    visitIndex++;
    Arrays.fill(dijkstraResult, Long.MAX_VALUE);
    lastEdge[destination] = -1;
    dijkstraResult[source] = 0;
    for (int i = 0; i < vertexCount; i++) {
      int index = -1;
      long length = Long.MAX_VALUE;
      for (int j = 0; j < vertexCount; j++) {
	if (visited[j] != visitIndex && dijkstraResult[j] < length) {
	  length = dijkstraResult[j];
	  index = j;
	}
      }
      if (index == -1) {
	return;
      }
      visited[index] = visitIndex;
      int edgeID = graph.firstOutbound(index);
      while (edgeID != -1) {
	if (graph.capacity(edgeID) != 0) {
	  int next = graph.destination(edgeID);
	  if (visited[next] != visitIndex) {
	    long total = graph.weight(edgeID) - phi[next] + phi[index] + length;
	    if (dijkstraResult[next] > total) {
	      dijkstraResult[next] = total;
	      lastEdge[next] = edgeID;
	    }
	  }
	}
	edgeID = graph.nextOutbound(edgeID);
      }
    }
  }
}

class Pair<U, V> implements Comparable<Pair<U, V>> {
  public final U first;
  public final V second;

  public static<U, V> Pair<U, V> makePair(U first, V second) {
    return new Pair<U, V>(first, second);
  }

  private Pair(U first, V second) {
    this.first = first;
    this.second = second;
  }

  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Pair pair = (Pair) o;

    return !(first != null ? !first.equals(pair.first) : pair.first != null) && !(second != null ? !second.equals(pair.second) : pair.second != null);

  }

  public int hashCode() {
    int result = first != null ? first.hashCode() : 0;
    result = 31 * result + (second != null ? second.hashCode() : 0);
    return result;
  }

  public String toString() {
    return "(" + first + "," + second + ")";
  }

  public int compareTo(Pair<U, V> o) {
    int value = ((Comparable<U>)first).compareTo(o.first);
    if (value != 0)
      return value;
    return ((Comparable<V>)second).compareTo(o.second);
  }
}

abstract class IntCollection {
  public abstract IntIterator iterator();
  public abstract int size();
  public abstract void add(int value);

  public void addAll(IntCollection values) {
    for (IntIterator it = values.iterator(); it.isValid(); it.advance()) {
      add(it.value());
    }
  }

}

interface IntIterator {
  public int value() throws NoSuchElementException;
  /*
   * @throws NoSuchElementException only if iterator already invalid
   */
  public void advance() throws NoSuchElementException;
  public boolean isValid();
}

interface Edge {
}

abstract class IntList extends IntCollection implements Comparable<IntList> {

  public abstract int get(int index);

  public IntIterator iterator() {
    return new IntIterator() {
      private int size = size();
      private int index = 0;

      public int value() throws NoSuchElementException {
	if (!isValid())
	  throw new NoSuchElementException();
	return get(index);
      }

      public void advance() throws NoSuchElementException {
	if (!isValid())
	  throw new NoSuchElementException();
	index++;
      }

      public boolean isValid() {
	return index < size;
      }
    };
  }

  public int hashCode() {
    int hashCode = 1;
    for (IntIterator i = iterator(); i.isValid(); i.advance())
      hashCode = 31 * hashCode + i.value();
    return hashCode;
  }

  public boolean equals(Object obj) {
    if (!(obj instanceof IntList))
      return false;
    IntList list = (IntList)obj;
    if (list.size() != size())
      return false;
    IntIterator i = iterator();
    IntIterator j = list.iterator();
    while (i.isValid()) {
      if (i.value() != j.value())
	return false;
      i.advance();
      j.advance();
    }
    return true;
  }

  public int compareTo(IntList o) {
    IntIterator i = iterator();
    IntIterator j = o.iterator();
    while (true) {
      if (i.isValid()) {
	if (j.isValid()) {
	  if (i.value() != j.value()) {
	    if (i.value() < j.value())
	      return -1;
	    else
	      return 1;
	  }
	} else
	  return 1;
      } else {
	if (j.isValid())
	  return -1;
	else
	  return 0;
      }
      i.advance();
      j.advance();
    }
  }

}

class IntArrayList extends IntList {
  private int[] array;
  private int size;

  public IntArrayList() {
    this(10);
  }

  public IntArrayList(int capacity) {
    array = new int[capacity];
  }

  public IntArrayList(IntList list) {
    this(list.size());
    addAll(list);
  }

  public int get(int index) {
    if (index >= size)
      throw new IndexOutOfBoundsException();
    return array[index];
  }

  public int size() {
    return size;
  }

  public void add(int value) {
    ensureCapacity(size + 1);
    array[size++] = value;
  }

  public void ensureCapacity(int newCapacity) {
    if (newCapacity > array.length) {
      int[] newArray = new int[Math.max(newCapacity, array.length << 1)];
      System.arraycopy(array, 0, newArray, 0, size);
      array = newArray;
    }
  }

}

interface IntComparator {

}

class IntegerUtils {

  public static int longCompare(long a, long b) {
    if (a < b)
      return -1;
    if (a > b)
      return 1;
    return 0;
  }

}


//package abbyycup2013;
import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class ProblemC1 {
    BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    PrintWriter writer = new PrintWriter(new OutputStreamWriter(System.out));

    ProblemC1() throws IOException {
//        reader = new BufferedReader(new FileReader("input.txt"));
//        writer = new PrintWriter(new FileWriter("output.txt"));
    }

    int[] readInts() throws IOException {
        String[] strings = reader.readLine().split(" ");
        int[] ints = new int[strings.length];
        for(int i = 0; i < ints.length; i++) {
            ints[i] = Integer.parseInt(strings[i]);
        }
        return ints;
    }

    int[] tt = null;
    int tx = 0;
    int readInt() throws IOException {
        if(tt == null || tx >= tt.length) {
            tt = readInts();
            tx = 0;
        }
        return tt[tx++];
    }

    boolean isBit(int x, int bit) {
        return ((x >> bit) & 1) > 0;
    }

    void solve() throws IOException {
        int n = readInt();
        int m = readInt();
        int[][] table = new int[n][];
        for(int i = 0; i < n; i++) table[i] = readInts();
        int[][][] dp = new int[n + 1][m][1 << m];
        for(int i = 0; i <= n; i++) for(int j = 0; j < m; j++) for(int k = 0; k < 1 << m; k++) dp[i][j][k] = Integer.MAX_VALUE;
        dp[0][0][0] = 0;
        int inf = Integer.MAX_VALUE;
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < m; j++) {
                for(int mask = 0; mask < 1 << m; mask++) {
                    if(dp[i][j][mask] == inf) continue;
                    if(isBit(mask, j)) {
                        int newJ = j + 1;
                        int newI = i;
                        if(newJ == m) {
                            newI++;
                            newJ = 0;
                        }
                        int newMask = mask ^ (1 << j);
                        dp[newI][newJ][newMask] = Math.min(dp[newI][newJ][newMask], dp[i][j][mask]);
                    }
                    else {
                        if(i + 1 < n) {
                            int newJ = j + 1;
                            int newI = i;
                            if(newJ == m) {
                                newI++;
                                newJ = 0;
                            }
                            int newMask = mask ^ (1 << j);
                            dp[newI][newJ][newMask] = Math.min(dp[newI][newJ][newMask], dp[i][j][mask] + (table[i][j] == table[i + 1][j] ? 0 : 1));
                        }
                        if(j + 1 < m && !isBit(mask, j + 1)) {
                            int newJ = j + 2;
                            int newI = i;
                            if(newJ == m) {
                                newI++;
                                newJ = 0;
                            }
                            int newMask = mask;
                            dp[newI][newJ][newMask] = Math.min(dp[newI][newJ][newMask], dp[i][j][mask] + (table[i][j] == table[i][j + 1] ? 0 : 1));
                        }
                    }
                }

            }
        }
        writer.println(dp[n][0][0]);
        writer.flush();
    }

    void multiSolve() throws IOException {
        int n = readInts()[0];
        for(int i = 0; i < n; i++) {
            solve();
        }
        writer.flush();
    }

    public static void main(String[] args) throws IOException{
        new ProblemC1().solve();
    }
}


import static java.lang.Double.parseDouble;
import static java.lang.Integer.parseInt;
import static java.lang.Long.parseLong;
import static java.lang.System.exit;
import static java.util.Arrays.fill;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class C {

	static BufferedReader in;
	static PrintWriter out;
	static StringTokenizer tok;

	static final int DI[] = {1, 0, -1, 0};
	static final int DJ[] = {0, 1, 0, -1};

	static class Pos implements Comparable<Pos> {
		final int i, j, dist;

		Pos(int i, int j, int dist) {
			this.i = i;
			this.j = j;
			this.dist = dist;
		}

		public int compareTo(Pos o) {
			return dist - o.dist;
		}
	}

	static void solve() throws Exception {
		int n = nextInt();
		int m = nextInt();
		int id[][] = new int[n][m];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				id[i][j] = nextInt() - 1;
			}
		}
		int cap[][][] = new int[n][m][4];
		int cost[][][] = new int[n][m][4];
		int imbalance[][] = new int[n][m];
		int totalCost = n * m / 2;
		int totalImbalance = 0;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (((i ^ j) & 1) != 0) {
					--imbalance[i][j];
					continue;
				}
				++imbalance[i][j];
				for (int d = 0; d < 4; d++) {
					int ii = i + DI[d];
					int jj = j + DJ[d];
					if (ii < 0 || ii >= n || jj < 0 || jj >= m) {
						continue;
					}
					if (id[i][j] == id[ii][jj]) {
						cap[ii][jj][d ^ 2] = 1;
						cost[ii][jj][d ^ 2] = 1;
						cost[i][j][d] = -1;
						--imbalance[i][j];
						++imbalance[ii][jj];
						--totalCost;
					} else {
						cap[i][j][d] = 1;
					}
				}
				totalImbalance += imbalance[i][j];
			}
		}
		int dist[][] = new int[n][m];
		int distAdj[][] = new int[n][m];
		int back[][] = new int[n][m];
		PriorityQueue<Pos> queue = new PriorityQueue<>();
		while (totalImbalance > 0) {
			for (int t[]: dist) {
				fill(t, Integer.MAX_VALUE);
			}
			for (int t[]: back) {
				fill(t, -1);
			}
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < m; j++) {
					if (imbalance[i][j] > 0) {
						dist[i][j] = 0;
						queue.add(new Pos(i, j, 0));
					}
				}
			}
			do {
				Pos pos = queue.remove();
				int i = pos.i;
				int j = pos.j;
				int cdist = pos.dist;
				if (dist[i][j] != cdist) {
					continue;
				}
				for (int d = 0; d < 4; d++) {
					if (cap[i][j][d] == 0) {
						continue;
					}
					int ii = i + DI[d];
					int jj = j + DJ[d];
					int ndist = cdist + cost[i][j][d] + distAdj[ii][jj] - distAdj[i][j];
					if (ndist < cdist) {
						throw new AssertionError();
					}
					if (dist[ii][jj] > ndist) {
						dist[ii][jj] = ndist;
						back[ii][jj] = d ^ 2;
						queue.add(new Pos(ii, jj, ndist));
					}
				}
			} while (!queue.isEmpty());
			int resDist = Integer.MAX_VALUE;
			int resI = -1;
			int resJ = -1;
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < m; j++) {
					if (imbalance[i][j] < 0 && resDist > dist[i][j]) {
						resDist = dist[i][j];
						resI = i;
						resJ = j;
					}
				}
			}
			if (resDist == Integer.MAX_VALUE) {
				throw new AssertionError();
			}
			{
				int i = resI, j = resJ;
				++imbalance[i][j];
				while (true) {
					int d = back[i][j];
					int ii = i + DI[d];
					int jj = j + DJ[d];
					++cap[i][j][d];
					--cap[ii][jj][d ^ 2];
					i = ii;
					j = jj;
					if (imbalance[i][j] > 0) {
						break;
					}
				}
				--imbalance[i][j];
				--totalImbalance;
				totalCost += dist[resI][resJ] - distAdj[resI][resJ] - dist[i][j] + distAdj[i][j];
			}
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < m; j++) {
					if (dist[i][j] != Integer.MAX_VALUE) {
						distAdj[i][j] -= dist[i][j];
					}
				}
			}
		}
		out.print(totalCost);
	}

	static int nextInt() throws IOException {
		return parseInt(next());
	}

	static long nextLong() throws IOException {
		return parseLong(next());
	}

	static double nextDouble() throws IOException {
		return parseDouble(next());
	}

	static String next() throws IOException {
		while (tok == null || !tok.hasMoreTokens()) {
			tok = new StringTokenizer(in.readLine());
		}
		return tok.nextToken();
	}

	public static void main(String[] args) {
		try {
			in = new BufferedReader(new InputStreamReader(System.in));
			out = new PrintWriter(new OutputStreamWriter(System.out));
			solve();
			in.close();
			out.close();
		} catch (Throwable e) {
			e.printStackTrace();
			exit(1);
		}
	}
}


import java.util.Scanner;

public class Main {
    private static int m;
    private static int size=1;
    private static int[] que=new int[(80*80+5)*8];   //队列
    //dis 表示最小花费
    private static int[] dis=new int[80*80+5],pr = new int[80*80+5];
    //vis 表示是否访问过
    private static int[] ed=new int[80*80+5],vis = new int[80*80+5];
    private static int[] edge=new int[80*80+5],next = new int[80*80+5];
    //cost 表示单位流量费用  weight 表示剩余容量
    private static int[] cost=new int[80*80+5],weight = new int[80*80+5],pre = new int[80*80+5];

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        m =scan.nextInt();
        int s = n*m+1,t=n*m+2;
        int[][] a = new int[80+5][80+5];
        for (int i=1;i<=n;i++){
            for (int j=1;j<= m;j++){
                a[i][j] = scan.nextInt();
            }
        }
        for (int i=1;i<=n;i++){
            for (int j=1;j<=m;j++){
                if ((i+j)%2!=0){                //i+j为奇数分到s（起点）那一拨
                    addedge2(s,getNo(i,j),1,0);
                }else {                     //i+j为偶数分到t（终点）那一拨
                    addedge2(getNo(i,j),t,1,0);
                }
                if (j<m) {
                    if ((i+j)%2!=0) addedge2(getNo(i,j),getNo(i,j+1),1,isok(a[i][j],a[i][j+1]));
                    else addedge2(getNo(i,j+1),getNo(i,j),1,isok(a[i][j],a[i][j+1]));
                }
                if (i<n) {
                    if ((i+j)%2!=0) addedge2(getNo(i,j),getNo(i+1,j),1,isok(a[i][j],a[i+1][j]));
                    else addedge2(getNo(i+1,j),getNo(i,j),1,isok(a[i][j],a[i+1][j]));
                }
            }
        }

        int out = Costflow(s,t);
        System.out.println(out);
    }

    private static int Costflow(int s, int t) {
        int totcost=0;
        while (SPFA(s,t)) {
            int flow= 0x7f7f7f7f;
            for(int x=t;x!=s;x=pr[x]){
                flow=Math.min(flow,weight[ed[x]]);
            }
            totcost+=flow*dis[t];
            for(int x=t;x!=s;x=pr[x]){
                weight[ed[x]]-=flow;
                weight[ed[x]^1]+=flow;
            }
        }
        return totcost;

    }

    private static boolean SPFA(int s, int t) {
        for (int i=0;i<dis.length;i++){
            dis[i]= 127;
        }
        for (int i=0;i<vis.length;i++){
            vis[i]= 0;
        }

        dis[que[1]=s]=0;vis[s]=1;
        int head=1,tail=1;
        while (head<=tail) {
            int getNow=que[head++];
            for(int p=pre[getNow];p!=0;p=next[p]) {
                int v=edge[p];
                if (weight[p]>0&&dis[getNow]+cost[p]<dis[v]) {  //存在路径，且权值变小。
                    dis[v]=dis[getNow]+cost[p];
                    if (vis[v]==0){ vis[v]=1;que[++tail]=v;}
                    pr[v]=getNow;
                    ed[v]=p;
                }
            }
            vis[getNow]=0;
        }
        return dis[t]<dis[0];

    }

    private static int isok(int i, int j) {   //判断相邻两格是否相同，相同费用为0，不同为1
        if (i!=j){
            return 1;
        }else {
            return 0;
        }
    }

    private static void addedge2(int u, int v, int w, int c) {
        addedge(u,v,w,c);
        addedge(v,u,0,-c);
    }

    private static void addedge(int u, int v, int w, int c) {
        edge[++size]=v;
        weight[size]=w;
        cost[size]=c;
        next[size]=pre[u];
        pre[u]=size;
    }

    private static int getNo(int i, int j) {
        return (i-1)*m+j;
    }
}