import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

// 1 -> n/2  XX n/2 + 1 -> n
public class MotherOfDragons
{
	static boolean[][] adjMatrix;
	public static void main(String[] args) throws IOException
	{
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int k = sc.nextInt();
//		for (int i = 1; i <= n; i++)
//			System.err.printf("%d %.12f\n",i, (k*k*((i-1)/(2.0*i))));
		adjMatrix = new boolean[n][n];
		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				adjMatrix[i][j] = sc.nextInt() == 1;

		long[] edges = new long[n];
		for (int i = 0; i < n; i++)
		{
			long val = 0;
			for (int j = 0; j < n; j++)
				if(adjMatrix[i][j] || i == j)
					val |= 1l<<j;
			edges[i] = val;
		}

		int h = n/2;

		int[] cliques = new int[1<<h];
		for (int i = 1; i < 1<<h; i++)
		{
			int nodes = i;
			for (int j = 0; j < h; j++)
				if((i & (1 << j)) != 0)
					nodes &= edges[j];
			if(nodes == i)
				cliques[i] = Integer.bitCount(i);
		}

		for (int i = 1; i < 1<<h; i++)
			for (int j = 0; j < h; j++)
				if((i & (1 << j)) != 0)
					cliques[i] = Math.max(cliques[i], cliques[i ^ (1<<j)]);

		int max = 0;
		for (int i = 0; i < cliques.length; i++)
			max = Math.max(max, cliques[i]);
		for (int i = 1; i < 1<<(n-h); i++)
		{
			long all = -1l;
			long tmp = (1l*i)<<h;
			for (int j = h; j < n; j++)
				if((tmp & (1l << j)) != 0)
					all &= edges[j];
			long node = all&tmp;
			if(node != tmp)
				continue;
			int connected = (int)(all & ((1<<h)-1));
			max = Math.max(max, cliques[connected] + Integer.bitCount(i));
		}

		System.out.printf("%.12f\n", (k*k*((max-1)/(2.0*max))));
	}

	static class Scanner
	{
		StringTokenizer st;
		BufferedReader br;

		public Scanner(InputStream s)
		{
			br = new BufferedReader(new InputStreamReader(s));
		}

		public Scanner(String s) throws FileNotFoundException
		{
			br = new BufferedReader(new FileReader(new File((s))));
		}

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

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

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

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

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


import java.util.*;
import java.io.*;
public class E {
    void solve(BufferedReader in) throws Exception {
        int[] xx = toInts(in.readLine());
        int n = xx[0];
        double k = xx[1];
        int[][] board = new int[n][n];
        for(int i = 0; i<n; i++) board[i] = toInts(in.readLine());
        int fst = n/2;
        int snd = n - fst;
        int[] maxc = new int[1<<fst];
        int max = 1;
        for(int i = 0; i<(1<<fst); i++) {
            for(int j = 0; j<fst; j++) {
                if((i&(1<<j)) != 0) maxc[i] = Math.max(maxc[i], maxc[i^(1<<j)]);
            }
            boolean ok = true;
            for(int a = 0; a<fst; a++) if(((1<<a)&i) != 0) {
                for(int b = a+1; b<fst; b++) if(((1<<b)&i) != 0) {
                    if(board[a][b] == 0) ok = false;
                }
            }
            if(ok) {
                maxc[i] = Integer.bitCount(i);
                max = Math.max(max, maxc[i]);
            }
        }
        for(int i = 0; i<(1<<snd); i++) {
            boolean ok = true;
            for(int a = 0; a<snd; a++) if(((1<<a)&i) != 0) {
                for(int b = a+1; b<snd; b++) if(((1<<b)&i) != 0) {
                    if(board[a+fst][b+fst] == 0) ok = false;
                }
            }
            if(!ok) continue;
            int mask = 0;
            for(int a = 0; a<fst; a++) {
                ok = true;
                for(int b = 0; b<snd; b++) {
                    if(((1<<b)&i) != 0) {
                        if(board[a][b+fst] == 0) ok = false;
                    }
                }
                if(ok) mask |= (1<<a);
            }
            max = Math.max(Integer.bitCount(i) + maxc[mask], max);
        }
        System.out.println(k*k*(max-1.0)/(2*max));
    }
    int toInt(String s) {return Integer.parseInt(s);}
    int[] toInts(String s) {
        String[] a = s.split(" ");
        int[] o = new int[a.length];
        for(int i = 0; i<a.length; i++) o[i] = toInt(a[i]);
        return o;
    }
    void e(Object o) {
        System.err.println(o);
    }
    public static void main(String[] args) throws Exception{
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        (new E()).solve(in);
    }
}


import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.StringTokenizer;

public class ELR {

	static double solveUnweighted (int nodes, long curr, long pool, long excl) {
		if (pool == 0 && excl == 0) {
			int cnt = 0;
			for (int i = 0; i < nodes; i++)
				if ((curr & 1L << i) > 0)
					cnt++;

			double cont = (k / (cnt*1.0));
			double edges = (cnt) * (cnt - 1) / 2.0;
			return cont * cont * edges;
		}
		double res = 0;
		int j = 0;
		for (int i = 0; i < nodes; i++)
			if ((pool & 1L << i) > 0 || (excl & 1L << i) > 0)
				j = i;

		for (int i = 0; i < nodes; i++) {
			if ((pool & 1L << i) == 0 || adj[i][j])
				continue;
			long ncurr = curr, npool = 0, nexcl = 0;
			ncurr |= 1L << i;

			for (int k = 0; k < nodes; k++) {
				if (adj[i][k]) {
					npool |= pool & 1L << k;
					nexcl |= excl & 1L << k;
				}
			}
			res = Math.max(res, solveUnweighted(nodes, ncurr, npool, nexcl));

			pool &= ~(1L << i);
			excl |= 1L >> i;
		}
		return res;
	}
	public static void main(String[] args) {new Thread(null, new Runnable() { public void run() {try {
		sol();
	} catch (Throwable e) {

		e.printStackTrace();
	}}}, "2",1<<26).start();}

	static int n,k;
	static boolean adj[][];
	public static void sol() throws Throwable {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		k = sc.nextInt();
		adj = new boolean[n][n];
		for (int i = 0 ; i < n ; ++i) {
			for (int j = 0 ; j < n ; ++j) {
				adj[i][j] = sc.nextInt() == 1;
			}
		}
		double ans = solveUnweighted(n, 0, (1L << n) - 1, 0);
		System.out.println(ans);
	}

	static class Scanner {
		StringTokenizer st;
		BufferedReader br;

		public Scanner(InputStream s) {
			br = new BufferedReader(new InputStreamReader(s));
		}

		public Scanner(String s) throws FileNotFoundException {
			br = new BufferedReader(new FileReader(new File(s)));
		}

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

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

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

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

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

		public boolean ready() throws IOException {
			return br.ready();
		}
	}
}


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 (PloadyFree@gmail.com)
 */
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);
        TaskE solver = new TaskE();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskE {
        int n;
        double k;
        boolean[][] g;

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            n = in.readInt();
            k = in.readInt();

            g = new boolean[n][n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    g[i][j] = in.readInt() == 1;
                }
            }

            double answer = solve();
            out.printFormat("%.20f", answer);
        }

        private double solve() {
            int firstPartSize = g.length / 2;
            int secondPartSize = g.length - firstPartSize;

            int[] firstPart = findMaxCliqueSize(firstPartSize);

            int m1Full = (1 << firstPartSize) - 1;
            int maxCliqueSize = 1;
            for (int m = 0; m < 1 << secondPartSize; m++) {
                if (isClique(secondPartSize, m, firstPartSize)) {
                    int m1 = m1Full;
                    for (int j = 0; j < secondPartSize; j++) {
                        if (bit(m, j)) {
                            for (int i = 0; i < firstPartSize; i++) {
                                if (bit(m1, i) && !g[i][j + firstPartSize]) {
                                    m1 ^= 1 << i;
                                }
                            }
                        }
                    }
                    int firstCliqueSize = firstPart[m1];
                    int secondCliqueSize = Integer.bitCount(m);
                    int curCliqueSize = firstCliqueSize + secondCliqueSize;
                    if (curCliqueSize > maxCliqueSize) {
                        maxCliqueSize = curCliqueSize;
                    }
                }
            }

            return k * k * (maxCliqueSize - 1) / (2 * maxCliqueSize);
        }

        private int[] findMaxCliqueSize(int size) {
            int[] dp = new int[1 << size];
            for (int m = 1; m < 1 << size; m++) {
                if (isClique(size, m, 0)) {
                    dp[m] = Integer.bitCount(m);
                }
            }
            for (int m = 1; m < 1 << size; m++) {
                for (int i = 0; i < size; i++) {
                    if ((m >> i & 1) == 0) {
                        dp[m | (1 << i)] = Math.max(dp[m | (1 << i)], dp[m]);
                    }
                }
            }
            return dp;
        }

        private boolean isClique(int size, int m, int offset) {
            for (int i = 0; i < size; i++) {
                if (bit(m, i)) {
                    for (int j = i + 1; j < size; j++) {
                        if (bit(m, j) && !g[i + offset][j + offset]) {
                            return false;
                        }
                    }
                }
            }
            return true;
        }

        private boolean bit(int m, int b) {
            return (m >> b & 1) != 0;
        }

    }

    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);

        }

    }

    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 printFormat(String format, Object... objects) {
            writer.printf(format, objects);
        }

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

    }
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.IOException;
import java.util.StringTokenizer;
/*
 * @author Tnascimento
 */

public class MaeDosDragoes {
	public static PrintWriter saida = new PrintWriter(System.out, false);
	public static class Escanear {
        BufferedReader reader;
        StringTokenizer tokenizer;
		public Escanear() {
            this(new InputStreamReader(System.in));
        }
		public Escanear(Reader in) {
            reader = new BufferedReader(in);
        }
        String proximo() {
            if (tokenizer == null || !tokenizer.hasMoreElements()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return tokenizer.nextToken();
        }

        int proximoNum() {
            return Integer.parseInt(proximo());
        }
    }

    public static void main(String[] args) {
		Escanear escanear = new Escanear();
        int proximoInt = escanear.proximoNum();
        double proximoDouble = escanear.proximoNum();
        long[] aux = new long[proximoInt];
        for(Integer i = 0; i < proximoInt; i++) {
            for(Integer j =0; j < proximoInt; j++) {
                Integer val = escanear.proximoNum();
                if (val.equals(1) || i.equals(j)) {
				 aux[i] |= 1L << j;
				}
            }
        }

        int esquerda = proximoInt/2;
        int direita = proximoInt - esquerda;

        int[] depois = new int[1 << esquerda];
        int maiorMascara = 1 << esquerda;

        for(int mascara = 1; mascara <maiorMascara; mascara++) {
            int mascaraAtual = mascara;

            for(int j = 0; j < esquerda; j++) {
                if (((1 << j) & mascara) > 0) {
                    mascaraAtual &= aux[j + direita] >> direita;
                    depois[mascara] = Math.max(depois[mascara], depois[mascara ^ (1 << j)]);
                }
            }
            if (mascara == mascaraAtual) {
                depois[mascara] = Math.max(depois[mascara],Integer.bitCount(mascara));
            }
        }
        int auxiliar = 0;
        int mascaraMaxima = 1 << direita;
        for(int mascara = 0; mascara < mascaraMaxima; mascara++) {
            int mascaraCorrente = mascara;
            int mascaraValor = maiorMascara -1;
            for(int j = 0; j < direita; j++) {
                if (((1 << j) & mascara) > 0) {
                    mascaraCorrente &= (aux[j] & (mascaraMaxima-1));
                    mascaraValor &= aux[j] >> direita;
                }
            }
            if (mascaraCorrente != mascara) continue;
            auxiliar = Math.max(auxiliar, Integer.bitCount(mascara) + depois[mascaraValor]);
        }
        proximoDouble/=auxiliar;
        saida.println(proximoDouble * proximoDouble * (auxiliar * (auxiliar-1))/2);
        saida.flush();
    }
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.IOException;
import java.util.StringTokenizer;
/*
 * @author Tnascimento
 */

public class MaeDosDragoes {
	public static PrintWriter saida = new PrintWriter(System.out, false);
	public static class Escanear {
        BufferedReader reader;
        StringTokenizer tokenizer;
		public Escanear() {
            this(new InputStreamReader(System.in));
        }
		public Escanear(Reader in) {
            reader = new BufferedReader(in);
        }
        String proximo() {
            if (tokenizer == null || !tokenizer.hasMoreElements()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return tokenizer.nextToken();
        }

        int proximoNum() {
            return Integer.parseInt(proximo());
        }
    }
    public static void main(String[] args) {
		Escanear escanear = new Escanear();
		int proximoInt = escanear.proximoNum();
        long[] aux = new long[proximoInt];
        double proximoDouble = escanear.proximoNum();
        for(Integer i = 0; i < proximoInt; i++) {
            for(Integer j =0; j < proximoInt; j++) {
                Integer val = escanear.proximoNum();
                if (val.equals(1) || i.equals(j)) {
				 aux[i] |= 1L << j;
				}
            }
        }
        int esquerda = proximoInt/2;
        int direita = proximoInt - esquerda;
		int maiorMascara = 1 << esquerda;
		int[] depois = new int[1 << esquerda];
		Integer mascara = 1;
		while (mascara < maiorMascara) {
			int mascaraAtual = mascara;
            for(int j = 0; j < esquerda; j++) {
                if (((1 << j) & mascara) > 0) {
                    mascaraAtual &= aux[j + direita] >> direita;
                    depois[mascara] = Math.max(depois[mascara], depois[mascara ^ (1 << j)]);
                }
            }
            if (mascara.equals(mascaraAtual)) {
                depois[mascara] = Math.max(depois[mascara],Integer.bitCount(mascara));
			}
			mascara++;
		}
        int auxiliar = 0;
        int mascaraMaxima = 1 << direita;
        for(int i = 0; i < mascaraMaxima; i++) {
            int mascaraCorrente = i;
            int mascaraValor = maiorMascara -1;
            for(int j = 0; j < direita; j++) {
                if (((1 << j) & i) > 0) {
                    mascaraCorrente &= (aux[j] & (mascaraMaxima-1));
                    mascaraValor &= aux[j] >> direita;
                }
            }
            if (mascaraCorrente != i) continue;
            auxiliar = Math.max(auxiliar, Integer.bitCount(i) + depois[mascaraValor]);
        }
        proximoDouble/=auxiliar;
        saida.println(proximoDouble * proximoDouble * (auxiliar * (auxiliar-1))/2);
        saida.flush();
    }
}


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

public class Solution {

	private static StringTokenizer st;
	private static int n;
	private static int k;

	private static boolean[][] graph;
	private static int[] dp;
	private static int maxCliqueSize;

	public static void main(String[] args) throws Exception {
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

		st = new StringTokenizer(reader.readLine());
		n = Integer.parseInt(st.nextToken());
		k = Integer.parseInt(st.nextToken());

		graph = new boolean[n][n];
		dp = new int[1 << (n / 2)];

		for (int i = 0; i < n; ++i) {
			st = new StringTokenizer(reader.readLine());

			for (int j = 0; j < n; ++j)
				graph[i][j] = st.nextToken().equals("1");
		}

		reader.close();

		/* fill dp for first subset */
		int size1 = n / 2;
		int border = 1 << size1;
		for (int mask = 1; mask < border; ++mask) {
			/* check if mask is complete graph */

			boolean isComplete = true;
			for (int i = 0; i < size1; ++i) {
				if (((mask >> i) & 1) == 0)
					continue;

				for (int j = i + 1; j < size1; ++j) {
					if (((mask >> j) & 1) == 0)
						continue;

					if (!graph[i][j]) {
						isComplete = false;
						break;
					}
				}

				if (!isComplete)
					break;
			}

			if (isComplete)
				dp[mask] = Integer.bitCount(mask);
		}

		for (int mask = 1; mask < border; ++mask) {
			for (int i = 0; i < size1; ++i) {
				if (((mask >> i) & 1) == 0) {
					dp[mask | (1 << i)] = Math.max(dp[mask | (1 << i)], dp[mask]);
				}
			}
		}

		/* process second subset */
		maxCliqueSize = 1;
		int size2 = n - n /2;
		border = (1 << size2);

		for (int mask = 0; mask < border; ++mask) {

			boolean isComplete = true;
			for (int i = 0; i < size2; ++i) {
				if (((mask >> i) & 1) == 0)
					continue;

				for (int j = i + 1; j < size2; ++j) {
					if (((mask >> j) & 1) != 0 && !graph[i + size1][j + size1]) {
						isComplete = false;
						break;
					}
				}

				if (!isComplete)
					break;
			}

			if (!isComplete)
				continue;

			int mask1 = (1 << size1) - 1;

			for (int i = 0; i < size2; ++i) {
				if (((mask >> i) & 1) == 0)
					continue;

				for (int j = 0; j < size1; ++j) {
					if (!graph[j][i + size1] && ((mask1 >> j) & 1) != 0)
						mask1 ^= (1 << j);
				}
			}

			maxCliqueSize = Math.max(maxCliqueSize, dp[mask1] + Integer.bitCount(mask));
		}

		// System.out.println(maxCliqueSize);
		double answer = (1.0 * k * k * (maxCliqueSize - 1) / (2 * maxCliqueSize));
		System.out.printf("%.15f", answer);
	}
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.StringTokenizer;

public class MotherOfDragons {
    public static void main(String[] args) {
        FastScanner scanner = new FastScanner();
        PrintWriter out = new PrintWriter(System.out, false);
        int n = scanner.nextInt();
        double k = scanner.nextInt();
        long[] graph = new long[n];
        for(Integer i = 0; i < n; i++) {
            for(Integer j =0; j < n; j++) {
                Integer val = scanner.nextInt();
                if (val.equals(1) || i.equals(j)) {
				 graph[i] |= 1L << j;
				}
            }
        }

        int szLeft = n/2;
        int szRight = n - szLeft;

        int[] dp = new int[1 << szLeft];
        int maxMask = 1 << szLeft;

        for(int mask = 1; mask <maxMask; mask++) {
            int curMask = mask;

            for(int j = 0; j < szLeft; j++) {
                if (((1 << j) & mask) > 0) {
                    curMask &= graph[j + szRight] >> szRight;
                    dp[mask] = Math.max(dp[mask], dp[mask ^ (1 << j)]);
                }
            }
            if (mask == curMask) {
                dp[mask] = Math.max(dp[mask],Integer.bitCount(mask));
            }
        }
        int ans = 0;
        int rmaxMask = 1 << szRight;
        for(int mask = 0; mask < rmaxMask; mask++) {
            int curMask = mask;
            int oMask = maxMask -1;
            for(int j = 0; j < szRight; j++) {
                if (((1 << j) & mask) > 0) {
                    curMask &= (graph[j] & (rmaxMask-1));
                    oMask &= graph[j] >> szRight;
                }
            }
            if (curMask != mask) continue;
            ans = Math.max(ans, Integer.bitCount(mask) + dp[oMask]);
        }
        k/=ans;
        out.println(k * k * (ans * (ans-1))/2);
        out.flush();
    }

    public static class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        public FastScanner(Reader in) {
            br = new BufferedReader(in);
        }

        public FastScanner() {
            this(new InputStreamReader(System.in));
        }

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

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

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

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

        String readNextLine() {
            String str = "";
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }
    }
}


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

public class E {

	public static void main(String[] args) throws IOException {
		Scanner sc=new Scanner(System.in);
		PrintWriter out=new PrintWriter(System.out);
		int n=sc.nextInt(),k=sc.nextInt();
		boolean [][]adj=new boolean[n][n];
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				adj[i][j]=sc.nextInt()==1;
		int n1=n/2,n2=n-n1;
		int []clique=new int [1<<n1];
		for(int msk=1;msk<1<<n1;msk++)
		{
			boolean ok=true;
			for(int i=0;i<n1;i++) if((msk & 1<<i) !=0)
				for(int j=i+1;j<n1;j++)
					if((msk & 1<<j) !=0 && !adj[i][j])
						ok=false;
			if(ok)
				clique[msk]=Integer.bitCount(msk);
		}

		int []edges=new int [n2];
		for(int i=0;i<n2;i++)
		{
			int msk=0;
			for(int j=0;j<n1;j++)
				if(adj[i+n1][j])
					msk|=1<<j;
			edges[i]=msk;
		}
		int max=0;
		for(int msk=1;msk<1<<n1;msk++)
			for(int i=0;i<n1;i++)
				if((msk & 1<<i) !=0)
					max=Math.max(max, clique[msk]=Math.max(clique[msk], clique[msk^(1<<i)]));

		for(int msk=1;msk<1<<n2;msk++)
		{
			int all=(1<<n1)-1;
			for(int j=0;j<n2;j++)
				if((msk & 1<<j) !=0)
					all &=edges[j];
			boolean ok=true;
			for(int i=0;i<n2;i++) if((msk & 1<<i) !=0)
				for(int j=i+1;j<n2;j++)
					if((msk & 1<<j) !=0 && !adj[i+n1][j+n1])
						ok=false;
			if(ok)
				max=Math.max(max, Integer.bitCount(msk)+clique[all]);

		}

		out.printf("%.9f\n",k*1.0*k*(max-1)/(2*max));

		out.close();

	}
	static class Scanner {
        StringTokenizer st;
        BufferedReader br;

        public Scanner(InputStream s) {
            br = new BufferedReader(new InputStreamReader(s));
        }

        public Scanner(FileReader s) {
            br = new BufferedReader(s);
        }

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

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

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

        public String nextLine() throws IOException {
            return br.readLine();
        }
        public boolean ready() throws IOException {return br.ready();}
        public double nextDouble() throws IOException {return Double.parseDouble(next());}

    }
}


import java.util.*;
import java.io.*;
public class E {
    void solve(BufferedReader in) throws Exception {
        int[] xx = toInts(in.readLine());
        int n = xx[0];
        double k = xx[1];
        int[][] board = new int[n][n];
        for(int i = 0; i<n; i++) board[i] = toInts(in.readLine());
        int fst = n/2;
        int snd = n - fst;
        int[] maxc = new int[1<<fst];
        int max = 1;
        for(int i = 0; i<(1<<fst); i++) {
            for(int j = 0; j<fst; j++) {
                if((i&1<<j) != 0) maxc[i] = Math.max(maxc[i], maxc[i^(1<<j)]);
            }
            boolean ok = true;
            for(int a = 0; a<fst; a++) if((i&1<<a) != 0) {
                for(int b = a+1; b<fst; b++) if((i&1<<b) != 0) {
                    if(board[a][b] == 0) ok = false;
                }
            }
            if(ok) {
                maxc[i] = Integer.bitCount(i);
                max = Math.max(max, maxc[i]);
            }
        }
        for(int i = 0; i<(1<<snd); i++) {
            boolean ok = true;
            for(int a = 0; a<snd; a++) if((i&1<<a) != 0) {
                for(int b = a+1; b<snd; b++) if((i&1<<b) != 0) {
                    if(board[a+fst][b+fst] == 0) ok = false;
                }
            }
            if(!ok) continue;
            int mask = 0;
            for(int a = 0; a<fst; a++) {
                ok = true;
                for(int b = 0; b<snd; b++) {
                    if((i&1<<b) != 0) {
                        if(board[a][b+fst] == 0) ok = false;
                    }
                }
                if(ok) mask |= (1<<a);
            }
            max = Math.max(Integer.bitCount(i) + maxc[mask], max);
        }
        System.out.println(k*k*(max-1.0)/(2*max));
    }
    int toInt(String s) {return Integer.parseInt(s);}
    int[] toInts(String s) {
        String[] a = s.split(" ");
        int[] o = new int[a.length];
        for(int i = 0; i<a.length; i++) o[i] = toInt(a[i]);
        return o;
    }
    void e(Object o) {
        System.err.println(o);
    }
    public static void main(String[] args) throws Exception{
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        (new E()).solve(in);
    }
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.IOException;
import java.util.StringTokenizer;
/*
 * @author Tnascimento
 */

public class MaeDosDragoes {
	// public static StringTokenizer tokenizer;
	// public static BufferedReader reader;
	public static PrintWriter saida = new PrintWriter(System.out, false);
	// public static String proximo() {
	// 	while (tokenizer == null || !tokenizer.hasMoreElements()) {
	// 		try {
	// 			tokenizer = new StringTokenizer(reader.readLine());
	// 		} catch (RuntimeException e) {
	// 			e.printStackTrace();
	// 		}
	// 	}
	// 	return tokenizer.nextToken();
	// }

	public static class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        public FastScanner(Reader in) {
            br = new BufferedReader(in);
        }

        public FastScanner() {
            this(new InputStreamReader(System.in));
        }

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

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

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

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

        String readNextLine() {
            String str = "";
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }
    }

    public static void main(String[] args) {
		FastScanner fastScanner = new FastScanner();
        int proximoInt = fastScanner.nextInt();
        double proximoDouble = fastScanner.nextInt();
        long[] graph = new long[proximoInt];
        for(Integer i = 0; i < proximoInt; i++) {
            for(Integer j =0; j < proximoInt; j++) {
                Integer val = fastScanner.nextInt();
                if (val.equals(1) || i.equals(j)) {
				 graph[i] |= 1L << j;
				}
            }
        }

        int szLeft = proximoInt/2;
        int szRight = proximoInt - szLeft;

        int[] dp = new int[1 << szLeft];
        int maxMask = 1 << szLeft;

        for(int mask = 1; mask <maxMask; mask++) {
            int curMask = mask;

            for(int j = 0; j < szLeft; j++) {
                if (((1 << j) & mask) > 0) {
                    curMask &= graph[j + szRight] >> szRight;
                    dp[mask] = Math.max(dp[mask], dp[mask ^ (1 << j)]);
                }
            }
            if (mask == curMask) {
                dp[mask] = Math.max(dp[mask],Integer.bitCount(mask));
            }
        }
        int ans = 0;
        int rmaxMask = 1 << szRight;
        for(int mask = 0; mask < rmaxMask; mask++) {
            int curMask = mask;
            int oMask = maxMask -1;
            for(int j = 0; j < szRight; j++) {
                if (((1 << j) & mask) > 0) {
                    curMask &= (graph[j] & (rmaxMask-1));
                    oMask &= graph[j] >> szRight;
                }
            }
            if (curMask != mask) continue;
            ans = Math.max(ans, Integer.bitCount(mask) + dp[oMask]);
        }
        proximoDouble/=ans;
        saida.println(proximoDouble * proximoDouble * (ans * (ans-1))/2);
        saida.flush();
    }
}


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

public class MotherOfDragons {
    public static void main(String[] args) {
        FastScanner scanner = new FastScanner();
        PrintWriter out = new PrintWriter(System.out, false);
        int n = scanner.nextInt();
        double k = scanner.nextInt();
        long[] graph = new long[n];
        for(int i = 0; i < n; i++) {
            for(int j =0; j < n; j++) {
                int val = scanner.nextInt();
                if (val == 1 || i == j) graph[i] |= 1L << j;
            }
        }
        //meet in the middle approach
        int szLeft = n/2;
        int szRight = n - szLeft;
        //max size of clique
        int[] dp = new int[1 << szLeft];
        int maxMask = 1 << szLeft;
        //iterate over every left mask
        for(int mask = 1; mask <maxMask; mask++) {
            int curMask = mask;
            //go over every bit in the mask
            for(int j = 0; j < szLeft; j++) {
                if (((1 << j) & mask) > 0) {
                    //update the union of reachability
                    curMask &= graph[j + szRight] >> szRight;
                    //can also attempt to pull from prev mask for max size
                    //will not be optimal if end update happens, but otherwise is useful for dp
                    dp[mask] = Math.max(dp[mask], dp[mask ^ (1 << j)]);
                }
            }
            //if the union of connectedness is the starting mask then we have a clique
            if (mask == curMask) {
                dp[mask] = Math.max(dp[mask],Integer.bitCount(mask));
            }
        }
        int ans = 0;
        int rmaxMask = 1 << szRight;
        for(int mask = 0; mask < rmaxMask; mask++) {
            //mask to track if the current creates its own clique
            int curMask = mask;
            //mask to track the connection between the halves
            int oMask = maxMask -1;
            for(int j = 0; j < szRight; j++) {
                if (((1 << j) & mask) > 0) {
                    //need to mask out the left side bits
                    curMask &= (graph[j] & (rmaxMask-1));
                    //update corresp avail in the left side
                    oMask &= graph[j] >> szRight;
                }
            }
            //not a clique portion
            if (curMask != mask) continue;
            //update answer
            ans = Math.max(ans, Integer.bitCount(mask) + dp[oMask]);
        }
        k/=ans;
        out.println(k * k * (ans * (ans-1))/2);
        out.flush();
    }

    public static class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        public FastScanner(Reader in) {
            br = new BufferedReader(in);
        }

        public FastScanner() {
            this(new InputStreamReader(System.in));
        }

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

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

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

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

        String readNextLine() {
            String str = "";
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }
    }
}


/**
 *
 * @author bossbelik
 */
import java.io.*;
import java.util.*;
import java.math.*;

public class Main{
    static long N = 100;
    static long CNT = 62;
    static long INF = 1 << 62;

    static long parsenum(long j, long l) {
        String k = "";
        long cur = 0;
        for (int i = (int) j; i <= l; ++i) {
            cur *= 10;
            cur += k.charAt(i) - '0';
        }
        return cur;
    }

    static long gcd(long a, long b) {
        if (b == 0) {
            return a;
        } else {
            return gcd(b, a % b);
        }
    }

    static boolean pri(int k) {
        if (k == 1) return false;
        for (int i = 2; i * i <= k; i++) {

            if (k % i == 0) return false;
        }
        return true;
    }

    static int[] calcz(String s) {
        int l = 0;
        int r = 0;
        int n = s.length();
        int z[] = new int[n];
        for (int i = 1; i < n; i++) {

            if (i <= r) {
                z[i] = Math.min(z[i - l], r - i + 1);
            }
            while (i + z[i] < n && s.charAt(z[i]) == s.charAt(i + z[i])) z[i]++;
            if (i + z[i] - 1 > r) {
                l = i;
                r = i + z[i] - 1;
            }

        }
        return z;
    }

    static int[] calcpref(String s) {
        int p[] = new int[s.length() + 1];
        int n = s.length();
        p[0] = 0;
        for (int i = 2; i <= n; i++) {
            p[i] = p[i - 1];
            while (p[i] > 0 && s.charAt(p[i]) != s.charAt(i - 1)) p[i] = p[p[i]];
            if (s.charAt(p[i]) == s.charAt(i - 1)) p[i]++;
        }
        return p;
    }
    static long MOD =  1000000007;

    static long binpow (long a, long n)
    {
        if (n == 0)
            return 1;
        if (n % 2 == 1)
            return binpow (a % MOD, (n-1) % MOD ) * a % MOD;
        else {
            long b = binpow(a % MOD, n/2 % MOD) % MOD;
            return (b * b) % MOD;
        }
    }

static int maxnum=105;
  static   int a[][] = new int[maxnum][maxnum];
  static   boolean used[] = new boolean[maxnum];
   static int curr , cnt ,n ,m;

 static    void dfs(int i)
    {
        int j;
        boolean flag;
        if(i > n)
        {
            cnt = curr;
            return ;
        }

        flag=true;
        for(j = 1 ; j < i; j++)
        {
            if (used[j] && a[j][i] == 0)
            {
                flag = false;
                break;
            }
        }
        if(flag)
        {
            curr++;
            used[i]=true;
            dfs(i+1);
            curr--;
        }
        if(curr + n - i > cnt)
        {
            used[i]=false;
            dfs(i+1);
        }
    }

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

//
        Scanner in = new Scanner(System.in);
        PrintWriter out = new PrintWriter((System.out));
        n = in.nextInt();
        m = in.nextInt();

            for(int i = 1 ; i <= n ; i++)
            {
                for (int j = 1; j <= n; j++)
                {
                    a[i][j] = in.nextInt();
                }
            }
            dfs(1);
           out.printf( "%.10f", (double) m * m * (cnt-1) / (2 * cnt ));

        out.println();
        out.close();
        return;
    }
}


import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.StringTokenizer;

public class ELR {

	public static void main(String[] args) {new Thread(null, new Runnable() { public void run() {try {
		sol();
	} catch (Throwable e) {

		e.printStackTrace();
	}}}, "2",1<<26).start();}

	static int n,k;
	static boolean adj[][];
	static int dp1[],dp2[];
	static int myMask[];
	static int next1[];
	static int m1,m2;
	public static int solve1(int msk) {
		if (dp1[msk] != -1) {
			return dp1[msk];
		}
		int ret = 0;
		int tmp = msk;
		for (int i = 0 ; i < m1 ; ++i) {
			if ( ((msk & (1 << i)) > 0)) {
				tmp &= (myMask[i]);
			}
		}
		if (tmp == msk) {
			ret = Integer.bitCount(msk);
		}
		for (int i = 0 ; i < m1 ; ++i) {
			if ( (msk & (1 << i)) > 0) {
				ret = Math.max(ret, solve1(msk & ~(1 << i)));
			}
		}
		return dp1[msk] = ret;
	}
	public static int solve2(int msk) {
		if (dp2[msk] != -1) {
			return dp2[msk];
		}
		int ret = 0;
		int tmp = msk;
		for (int i = 0 ; i < m2 ; ++i) {
			if ( ((msk & (1 << i)) > 0)) {
				tmp &= (myMask[i + m1]);
			}
		}
		if (tmp == msk) {
			ret = Integer.bitCount(msk);
		}
		for (int i = 0 ; i < m2 ; ++i) {
			if ( (msk & (1 << i)) > 0) {
				ret = Math.max(ret, solve2(msk & ~(1 << i)));
			}
		}
		return dp2[msk] = ret;
	}
	public static void sol() throws Throwable {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		k = sc.nextInt();
		adj = new boolean[n][n];
		for (int i = 0 ; i < n ; ++i) {
			for (int j = 0 ; j < n ; ++j) {
				adj[i][j] = sc.nextInt() == 1;
			}
		}

		m1= (n + 1) / 2;
		m2 = n - m1;
		dp1 = new int[1 << m1];
		dp2 = new int[1 << m2];
		next1 = new int[1 << m2];
		Arrays.fill(dp1, -1);
		Arrays.fill(dp2, -1);
		myMask = new int[n];
		for (int i = 0 ; i < n ; ++i) {
			if (i >= m1) {
				for (int j = m1 ; j < n ; ++j) {
					if (adj[i][j] || i == j) {
						myMask[i] |= (1 << (j - m1));
					}
				}
			} else {
				for (int j = m1 ; j < n ; ++j) {
					if (adj[i][j]) {
						next1[i] |= (1 << (j - m1));
					}
				}
				for (int j = 0 ; j < m1 ; ++j) {
					if (adj[i][j] || i == j) {
						myMask[i] |= (1 << j);
					}
				}
			}
		}
		for (int i = 0 ; i < (1 << m1) ; ++i) {
			solve1(i);
		}
		for (int i = 0 ; i < (1 << m2) ; ++i) {
			solve2(i);
		}
		int ans = 0;
		for (int msk = 0 ; msk < (1 << m1) ; ++msk) {
			int next = (1 << (m2)) - 1;
			if (dp1[msk] != Integer.bitCount(msk)) {
				continue;
			}
			for (int i = 0 ; i < m1 ; ++i) {
				if ( (msk & (1 << i)) > 0) {
					next &= next1[i];
				}
			}
			ans = Math.max(ans, dp1[msk] + dp2[next]);
		}
		double cont = (k / (ans*1.0));
		double edges = (ans) * (ans - 1) / 2.0;
		double res = cont * cont * edges;
		System.out.println(res);

	}

	static class Scanner {
		StringTokenizer st;
		BufferedReader br;

		public Scanner(InputStream s) {
			br = new BufferedReader(new InputStreamReader(s));
		}

		public Scanner(String s) throws FileNotFoundException {
			br = new BufferedReader(new FileReader(new File(s)));
		}

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

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

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

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

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

		public boolean ready() throws IOException {
			return br.ready();
		}
	}
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.IOException;
import java.util.StringTokenizer;
/*
 * @author Tnascimento
 */

public class MaeDosDragoes {
	public static PrintWriter saida = new PrintWriter(System.out, false);
	public static class Escanear {
        BufferedReader reader;
        StringTokenizer tokenizer;
		public Escanear() {
            this(new InputStreamReader(System.in));
        }
		public Escanear(Reader in) {
            reader = new BufferedReader(in);
        }
        String proximo() {
            if (tokenizer == null || !tokenizer.hasMoreElements()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return tokenizer.nextToken();
        }

        int proximoNum() {
            return Integer.parseInt(proximo());
        }
    }
    public static void main(String[] args) {
		Escanear escanear = new Escanear();
		int proximoInt = escanear.proximoNum();
        long[] aux = new long[proximoInt];
        double proximoDouble = escanear.proximoNum();
        for(Integer i = 0; i < proximoInt; i++) {
            for(Integer j =0; j < proximoInt; j++) {
                Integer val = escanear.proximoNum();
                if (val.equals(1) || i.equals(j)) {
				 aux[i] |= 1L << j;
				}
            }
        }
        int esquerda = proximoInt/2;
        int direita = proximoInt - esquerda;
		int maiorMascara = 1 << esquerda;
		int[] depois = new int[1 << esquerda];
		Integer mascara = 1;
		while (mascara < maiorMascara) {
			int mascaraAtual = mascara;
            for(int j = 0; j < esquerda; j++) {
                if (((1 << j) & mascara) > 0) {
                    mascaraAtual &= aux[j + direita] >> direita;
                    depois[mascara] = Math.max(depois[mascara], depois[mascara ^ (1 << j)]);
                }
            }
            if (mascara.equals(mascaraAtual)) {
                depois[mascara] = Math.max(depois[mascara],Integer.bitCount(mascara));
			}
			mascara++;
		}
        // for(int mascara = 1; mascara < maiorMascara; mascara++) {
        //     int mascaraAtual = mascara;

        //     for(int j = 0; j < esquerda; j++) {
        //         if (((1 << j) & mascara) > 0) {
        //             mascaraAtual &= aux[j + direita] >> direita;
        //             depois[mascara] = Math.max(depois[mascara], depois[mascara ^ (1 << j)]);
        //         }
        //     }
        //     if (mascara == mascaraAtual) {
        //         depois[mascara] = Math.max(depois[mascara],Integer.bitCount(mascara));
        //     }
        // }
        int auxiliar = 0;
        int mascaraMaxima = 1 << direita;
        for(int masc = 0; masc < mascaraMaxima; masc++) {
            int mascaraCorrente = masc;
            int mascaraValor = maiorMascara -1;
            for(int j = 0; j < direita; j++) {
                if (((1 << j) & masc) > 0) {
                    mascaraCorrente &= (aux[j] & (mascaraMaxima-1));
                    mascaraValor &= aux[j] >> direita;
                }
            }
            if (mascaraCorrente != masc) continue;
            auxiliar = Math.max(auxiliar, Integer.bitCount(masc) + depois[mascaraValor]);
        }
        proximoDouble/=auxiliar;
        saida.println(proximoDouble * proximoDouble * (auxiliar * (auxiliar-1))/2);
        saida.flush();
    }
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.IOException;
import java.util.StringTokenizer;
/*
 * @author Tnascimento
 */

public class MaeDosDragoes {
	public static PrintWriter saida = new PrintWriter(System.out, false);
	public static class Escanear {
        BufferedReader reader;
        StringTokenizer tokenizer;
		public Escanear() {
            this(new InputStreamReader(System.in));
        }
		public Escanear(Reader in) {
            reader = new BufferedReader(in);
        }
        String proximo() {
            while (tokenizer == null || !tokenizer.hasMoreElements()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return tokenizer.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(proximo());
        }

    }

    public static void main(String[] args) {
		Escanear fastScanner = new Escanear();
        int proximoInt = fastScanner.nextInt();
        double proximoDouble = fastScanner.nextInt();
        long[] graph = new long[proximoInt];
        for(Integer i = 0; i < proximoInt; i++) {
            for(Integer j =0; j < proximoInt; j++) {
                Integer val = fastScanner.nextInt();
                if (val.equals(1) || i.equals(j)) {
				 graph[i] |= 1L << j;
				}
            }
        }

        int szLeft = proximoInt/2;
        int szRight = proximoInt - szLeft;

        int[] dp = new int[1 << szLeft];
        int maxMask = 1 << szLeft;

        for(int mask = 1; mask <maxMask; mask++) {
            int curMask = mask;

            for(int j = 0; j < szLeft; j++) {
                if (((1 << j) & mask) > 0) {
                    curMask &= graph[j + szRight] >> szRight;
                    dp[mask] = Math.max(dp[mask], dp[mask ^ (1 << j)]);
                }
            }
            if (mask == curMask) {
                dp[mask] = Math.max(dp[mask],Integer.bitCount(mask));
            }
        }
        int ans = 0;
        int rmaxMask = 1 << szRight;
        for(int mask = 0; mask < rmaxMask; mask++) {
            int curMask = mask;
            int oMask = maxMask -1;
            for(int j = 0; j < szRight; j++) {
                if (((1 << j) & mask) > 0) {
                    curMask &= (graph[j] & (rmaxMask-1));
                    oMask &= graph[j] >> szRight;
                }
            }
            if (curMask != mask) continue;
            ans = Math.max(ans, Integer.bitCount(mask) + dp[oMask]);
        }
        proximoDouble/=ans;
        saida.println(proximoDouble * proximoDouble * (ans * (ans-1))/2);
        saida.flush();
    }
}


import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class E {

	static InputStream is;
	//String INPUT = "";

	public static void main(String[] args) throws IOException {
		is = System.in;
		int n = ni();
		int k = ni();

		int[][] aj = new int[n][n];

		for (int i = 0; i < aj.length; i++) {
			aj[i] = na(n);
		}

		int F = (n+1)/2;
		int B = n-F;

		int[] spanftf = new int[F];
		int[] spanftb = new int[F];
		for(int i =0; i < F; i++){
			for(int j =0; j < F; j++){
				if(i == j || aj[i][j] == 1){
					spanftf[i] |= 1<<j;
				}
			}
			for(int j =0; j< B; j++){
				if(aj[i][F+j] == 1){
					spanftb[i] |= 1<<j;
				}
			}
		}
		int[] maxes = new int[1<<B];
		for(int bm = 0; bm < (1<<F); bm++){
			int anded = (1<<F)-1;
			int spanToBack = (1<<B)-1;

			for(int i =0; i < F; i++){
				if((1<<i & bm) != 0){
					anded &= spanftf[i];
					spanToBack &= spanftb[i];
				}
			}

			if((anded & bm) == bm){
				maxes[spanToBack] = Math.max(maxes[spanToBack], Integer.bitCount(bm));
			}
		}
		int[] spanbtb = new int[B];
		for(int i =0; i < B; i++){
			for(int j =0; j< B; j++){
				if(aj[F+i][F+j] == 1 || i == j){
					spanbtb[i] |= 1<<j;
				}
			}
		}
		boolean[] isgood = new boolean[1<<B];
		for(int bm =0; bm < (1<<B); bm++){
			int anded = (1<<B)-1;

			for(int i =0; i < B; i++){
				if((1<<i & bm) != 0){
					anded &= spanbtb[i];
				}
			}

			if((anded & bm) == bm){
				isgood[bm] = true;
			}

		}
		bybc[] tosort = new bybc[1<<B];
		for (int i = 0; i < tosort.length; i++) {
			tosort[i]= new bybc(i);
		}
		Arrays.sort(tosort);

		int best = 1;
		for (int i = 0; i < tosort.length; i++) {
			int at  =tosort[i].mask;
			if(isgood[at]){
				best = Math.max(best, maxes[at]+Integer.bitCount(at));
			}

			for(int j =0; j < B; j++){
				if((1<<j & at) != 0){
					int to = at - (1<<j);
					maxes[to] = Math.max(maxes[to], maxes[at]);
				}
			}

		}

		//System.out.println("best: " + best);

		double ans= best*(best-1)/2.0 * (k*k/(double)(best*best));
		System.out.println(ans);
	}

	static class bybc implements Comparable<bybc>{
		int mask;

		public bybc(int mask) {
			super();
			this.mask = mask;
		}

		@Override
		public int compareTo(bybc o) {
			return Integer.bitCount(o.mask) - Integer.bitCount(mask);
		}
	}

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

	private static 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 static boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private static int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private static double nd() { return Double.parseDouble(ns()); }
	private static char nc() { return (char)skip(); }

	private static 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 static 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 static 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 static int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private static 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 static 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(!oj)System.out.println(Arrays.deepToString(o)); }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Random;
import java.io.IOException;
import java.io.Reader;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.InputStream;

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

    static class TaskE {
        int n;
        int k;
        long[] neigibor;
        Random random = new Random();
        long maxClique;

        public void solve(int testNumber, MyInput in, PrintWriter out) {
            n = in.nextInt();
            k = in.nextInt();
            neigibor = new long[n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    neigibor[i] |= in.nextLong() << j;
                }
            }
            long maxClique = bronKerbosch();
            long a = Long.bitCount(maxClique);
            dump(a);
            out.printf("%.12f\n", a * (a - 1.0) / 2 * k / a * k / a);
        }

        static void dump(Object... o) {
            System.err.println(Arrays.deepToString(o));
        }

        long bronKerbosch() {
            maxClique = 0;
            bronKerbosch2(0, (1L << n) - 1, 0);
            return maxClique;
        }

        void bronKerbosch2(long r, long p, long x) {
//        if (Long.bitCount(maxClique) >= Long.bitCount(r|p|x)) return;
            long px = p | x;
            if (px == 0) {
                if (Long.bitCount(maxClique) < Long.bitCount(r)) {
                    maxClique = r;
                }
                return;
            }
            int cnt = Long.bitCount(px);
            int choice = random.nextInt(cnt);
            int u;
            for (int i = 0; ; i++) {
                if ((px >>> i & 1) != 0 && choice-- == 0) {
                    u = i;
                    break;
                }
            }
//        dump(r, p, x, u, neigibor);
            long ne = p & ~neigibor[u];
            for (int v = 0; v < n; v++)
                if ((ne >>> v & 1) != 0) {
                    bronKerbosch2(r | 1L << v, p & neigibor[v], x & neigibor[v]);
                    p &= ~(1L << v);
                    x |= 1L << v;
                }
        }

    }

    static class MyInput {
        private final BufferedReader in;
        private static int pos;
        private static int readLen;
        private static final char[] buffer = new char[1024 * 8];
        private static char[] str = new char[500 * 8 * 2];
        private static boolean[] isDigit = new boolean[256];
        private static boolean[] isSpace = new boolean[256];
        private static boolean[] isLineSep = new boolean[256];

        static {
            for (int i = 0; i < 10; i++) {
                isDigit['0' + i] = true;
            }
            isDigit['-'] = true;
            isSpace[' '] = isSpace['\r'] = isSpace['\n'] = isSpace['\t'] = true;
            isLineSep['\r'] = isLineSep['\n'] = true;
        }

        public MyInput(InputStream is) {
            in = new BufferedReader(new InputStreamReader(is));
        }

        public int read() {
            if (pos >= readLen) {
                pos = 0;
                try {
                    readLen = in.read(buffer);
                } catch (IOException e) {
                    throw new RuntimeException();
                }
                if (readLen <= 0) {
                    throw new MyInput.EndOfFileRuntimeException();
                }
            }
            return buffer[pos++];
        }

        public int nextInt() {
            int len = 0;
            str[len++] = nextChar();
            len = reads(len, isSpace);
            int i = 0;
            int ret = 0;
            if (str[0] == '-') {
                i = 1;
            }
            for (; i < len; i++) ret = ret * 10 + str[i] - '0';
            if (str[0] == '-') {
                ret = -ret;
            }
            return ret;
        }

        public long nextLong() {
            int len = 0;
            str[len++] = nextChar();
            len = reads(len, isSpace);
            int i = 0;
            long ret = 0;
            if (str[0] == '-') {
                i = 1;
            }
            for (; i < len; i++) ret = ret * 10 + str[i] - '0';
            if (str[0] == '-') {
                ret = -ret;
            }
            return ret;
        }

        public char nextChar() {
            while (true) {
                final int c = read();
                if (!isSpace[c]) {
                    return (char) c;
                }
            }
        }

        int reads(int len, boolean[] accept) {
            try {
                while (true) {
                    final int c = read();
                    if (accept[c]) {
                        break;
                    }
                    if (str.length == len) {
                        char[] rep = new char[str.length * 3 / 2];
                        System.arraycopy(str, 0, rep, 0, str.length);
                        str = rep;
                    }
                    str[len++] = (char) c;
                }
            } catch (MyInput.EndOfFileRuntimeException e) {
            }
            return len;
        }

        static class EndOfFileRuntimeException extends RuntimeException {
        }

    }
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class C {

	static int[] nm;
	static int ans = 0;
	static int rows, cols;
	static boolean[][] cae;
	static int[][] ca;

	public static void main(String[] args) throws IOException {
		nm = readIntArray();
		rows = Math.max(nm[0], nm[1]);
		cols = Math.min(nm[0], nm[1]);

		long s = System.currentTimeMillis();
		cae = new boolean[1000][50];
		ca = new int[1000][50];

		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < cols; i++) {
			sb.append('1');
		}
		int startingState = Integer.parseInt(sb.toString(), 3);
		ans = solve(startingState, 0);

		System.out.println(nm[0]*nm[1] - ans);
//		System.out.println(System.currentTimeMillis() - s );
	}

	static int solve(int state, int row) {
		if (row == rows) {
			return 0;
		}
		if (cae[state][row]) {
			return ca[state][row];
		}

		int ans = Integer.MAX_VALUE;
		for (int i = 0; i < Math.pow(3, cols); i++) {
			boolean isCover = covers(i, state);
			if (isCover && (row < rows - 1 || coversTotally(i, state))) {
				int p = placed(i);
				int s = solve(i, row + 1);
				ans = Math.min(ans, s + p);
			}
		}

		cae[state][row] = true;
		ca[state][row] = ans;

		return ans;
	}

	private static boolean coversTotally(int i, int state) {

		String bottom = decode(i);
		for (int j = 0; j < bottom.length(); j++) {
			if (bottom.charAt(j) == '0') {
				return false;
			}
		}
		return true;
	}

	private static boolean covers(int i, int state) {
		String top = decode(state);
		String bottom = decode(i);

		for (int j = 0; j < top.length(); j++) {
			if (top.charAt(j) == '0' && bottom.charAt(j) != '2') {
				return false;
			}
			if (top.charAt(j) == '2' && bottom.charAt(j) == '0') {
				return false;
			}
		}

		for (int j = 0; j < top.length(); j++) {
			if (bottom.charAt(j) == '1' && (top.charAt(j) != '2' && !(j > 0 && bottom.charAt(j-1) == '2') && !(j < top.length() - 1 && bottom.charAt(j+1) == '2'))) {
				return false;
			}
		}

		return true;
	}

	private static int placed(int i) {
		String s = decode(i);
		int cnt = 0;
		for (int j = 0; j < s.length(); j++) {
			if (s.charAt(j) == '2') {
				cnt++;
			}
		}

		return cnt;
	}

	private static String decode(int state) {
		String tmp = Integer.toString(state, 3);
		if (tmp.length() < cols) {
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < cols - tmp.length(); i++) {
				sb.append('0');
			}
			sb.append(tmp);
			return sb.toString();
		} else {
			return tmp;
		}
	}

	static int countDispositionDivisors(int[] d) {
		HashSet<Integer> div = new HashSet<Integer>();
		for (int i = 1; i <= d.length; i++) {
			for (int j = 0; j < d.length; j++) {
				if ((j + 1) % i == 0 && d[j] % i == 0) {
					div.add(j + 1);
					break;
				}
			}
		}

		return div.size();
	}

	static InputStreamReader isr = new InputStreamReader(System.in);
	static BufferedReader br = new BufferedReader(isr);

	static int[] readIntArray() throws IOException {
		String[] v = br.readLine().split(" ");
		int[] ans = new int[v.length];

		for (int i = 0; i < ans.length; i++) {
			ans[i] = Integer.valueOf(v[i]);
		}

		return ans;
	}

	static long[] readLongArray() throws IOException {
		String[] v = br.readLine().split(" ");
		long[] ans = new long[v.length];

		for (int i = 0; i < ans.length; i++) {
			ans[i] = Long.valueOf(v[i]);
		}

		return ans;
	}

	static <T> void print(List<T> v) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < v.size(); i++) {
			if (sb.length() > 0) {
				sb.append(' ');
			}

			sb.append(v.get(i));
		}

		System.out.println(sb);
	}
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;

public class CodeJ
{
	static class Scanner
	{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer("");

		public String nextLine()
		{
			try
			{
				return br.readLine();
			}
			catch(Exception e)
			{
				throw(new RuntimeException());
			}
		}

		public String next()
		{
			while(!st.hasMoreTokens())
			{
				String l = nextLine();
				if(l == null)
					return null;
				st = new StringTokenizer(l);
			}
			return st.nextToken();
		}

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

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

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

		public int[] nextIntArray(int n)
		{
			int[] res = new int[n];
			for(int i = 0; i < res.length; i++)
				res[i] = nextInt();
			return res;
		}

		public long[] nextLongArray(int n)
		{
			long[] res = new long[n];
			for(int i = 0; i < res.length; i++)
				res[i] = nextLong();
			return res;
		}

		public double[] nextDoubleArray(int n)
		{
			double[] res = new double[n];
			for(int i = 0; i < res.length; i++)
				res[i] = nextLong();
			return res;
		}
		public void sortIntArray(int[] array)
		{
			Integer[] vals = new Integer[array.length];
			for(int i = 0; i < array.length; i++)
				vals[i] = array[i];
			Arrays.sort(vals);
			for(int i = 0; i < array.length; i++)
				array[i] = vals[i];
		}

		public void sortLongArray(long[] array)
		{
			Long[] vals = new Long[array.length];
			for(int i = 0; i < array.length; i++)
				vals[i] = array[i];
			Arrays.sort(vals);
			for(int i = 0; i < array.length; i++)
				array[i] = vals[i];
		}

		public void sortDoubleArray(double[] array)
		{
			Double[] vals = new Double[array.length];
			for(int i = 0; i < array.length; i++)
				vals[i] = array[i];
			Arrays.sort(vals);
			for(int i = 0; i < array.length; i++)
				array[i] = vals[i];
		}
	}

	static int nFilas;
	static int nColumnas;

	static byte[][][][][] dp;

	static byte dp(int mascaraActual, int enviadosActual, int enviadosSiguiente, int filaActual, int columnaActual)
	{
		if(dp[mascaraActual][enviadosActual][enviadosSiguiente][filaActual][columnaActual] != Byte.MAX_VALUE)
			return dp[mascaraActual][enviadosActual][enviadosSiguiente][filaActual][columnaActual];
		if(filaActual == nFilas)
			return dp[mascaraActual][enviadosActual][enviadosSiguiente][filaActual][columnaActual] = 0;
		if(columnaActual == nColumnas)
		{
			int ambos = mascaraActual & enviadosSiguiente;
			int mascaraSiguiente = (1 << nColumnas) - 1;
			mascaraSiguiente ^= ambos;
			int mascaraEnviados = enviadosSiguiente;
			mascaraEnviados ^= ambos;
			return dp[mascaraActual][enviadosActual][enviadosSiguiente][filaActual][columnaActual] = (byte) (nColumnas - Integer.bitCount(mascaraActual) + dp(mascaraSiguiente, mascaraEnviados, 0, filaActual + 1, 0));
		}
		if(((mascaraActual & (1 << columnaActual)) == 0))
		{
			// me envian desde abajo
			byte a = dp(mascaraActual | (1 << columnaActual), enviadosActual, enviadosSiguiente | (1 << columnaActual), filaActual, columnaActual + 1);
			// normal
			byte b = dp(mascaraActual, enviadosActual, enviadosSiguiente, filaActual, columnaActual + 1);
			return dp[mascaraActual][enviadosActual][enviadosSiguiente][filaActual][columnaActual] = (byte) Math.max(a, b);
		}
		if((enviadosActual & (1 << columnaActual)) != 0)
		{
			byte a = dp(mascaraActual, enviadosActual, enviadosSiguiente | (1 << columnaActual), filaActual, columnaActual + 1);
			byte b = dp(mascaraActual, enviadosActual, enviadosSiguiente, filaActual, columnaActual + 1);
			return dp[mascaraActual][enviadosActual][enviadosSiguiente][filaActual][columnaActual] = (byte) Math.max(a, b);
		}
		// izquierda
		byte ans = 0;
		if(columnaActual != 0)
			ans = (byte) Math.max(ans, dp((mascaraActual ^ (1 << columnaActual)) | (1 << (columnaActual - 1)), enviadosActual, enviadosSiguiente, filaActual, columnaActual + 1));
		// derecha
		if(columnaActual != nColumnas - 1)
			ans = (byte) Math.max(ans, dp((mascaraActual ^ (1 << columnaActual)) | (1 << (columnaActual + 1)), enviadosActual | (1 << (columnaActual + 1)), enviadosSiguiente, filaActual, columnaActual + 1));
		// abajo
		if(filaActual != nFilas - 1)
			ans = (byte) Math.max(ans, dp((mascaraActual ^ (1 << columnaActual)), enviadosActual, enviadosSiguiente | (1 << columnaActual), filaActual, columnaActual + 1));
		// quieto
		ans = (byte) Math.max(ans, dp(mascaraActual, enviadosActual, enviadosSiguiente, filaActual, columnaActual + 1));
		return dp[mascaraActual][enviadosActual][enviadosSiguiente][filaActual][columnaActual] = ans;
	}

	public static void main(String[] args)
	{
		Scanner sc = new Scanner();
		int a = sc.nextInt();
		int b = sc.nextInt();
		nFilas = Math.max(a, b);
		nColumnas = Math.min(a, b);
		dp = new byte[1 << nColumnas][1 << nColumnas][1 << nColumnas][nFilas + 1][nColumnas + 1];
		for(byte[][][][] i : dp)
			for(byte[][][] j : i)
				for(byte[][] k : j)
					for(byte[] l : k)
						Arrays.fill(l, Byte.MAX_VALUE);
		System.out.println(dp((1 << nColumnas) - 1, 0, 0, 0, 0));
	}
}


import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;
import static java.lang.Math.*;
import static java.util.Arrays.*;
import static java.util.Collections.*;

// Petya and Spiders
// 2012/08/16
public class P111C{
	Scanner sc=new Scanner(System.in);

	int INF=1<<28;
	double EPS=1e-9;

	int h, w;

	void run(){
		h=sc.nextInt();
		w=sc.nextInt();
		solve();
	}

	void solve(){
		n=w*h;
		g=new long[n];
		int[] dx={0, 0, -1, 1};
		int[] dy={-1, 1, 0, 0};
		for(int y=0; y<h; y++){
			for(int x=0; x<w; x++){
				for(int k=0; k<4; k++){
					int x2=x+dx[k];
					int y2=y+dy[k];
					if(x2>=0&&x2<w&&y2>=0&&y2<h){
						g[y*w+x]|=1L<<(y2*w+x2);
					}
				}
			}
		}
		mds=(1L<<n)-1;
		mds(0, 0, 0);
		println((n-Long.bitCount(mds))+"");
	}

	int n;
	long[] g;
	long mds;

	void mds(long choosed, long removed, long covered){
		if(Long.bitCount(choosed)>=Long.bitCount(mds))
			return;

		if(covered==((1L<<n)-1)){
			mds=choosed;
			return;
		}

		long s=covered;
		for(long remained=~removed&((1L<<n)-1); remained!=0; remained&=remained-1){
			int i=Long.numberOfTrailingZeros(remained);
			s|=(1L<<i)|g[i];
		}
		if(s!=((1L<<n)-1))
			return;

		int k=-1;
		for(long remained=~removed&((1L<<n)-1); remained!=0; remained&=remained-1){
			int i=Long.numberOfTrailingZeros(remained);
			if((covered>>>i&1)==1){
				if(Long.bitCount(g[i]&~covered)==0){
					mds(choosed, removed|(1L<<i), covered);
					return;
				}else if(Long.bitCount(g[i]&~covered)==1
						&&(g[i]&~covered&~removed)!=0){
					mds(choosed, removed|(1L<<i), covered);
					return;
				}
			}else{
				if(Long.bitCount(g[i]&~removed)==0){
					mds(choosed|(1L<<i), removed|(1L<<i), covered|(1L<<i)|g[i]);
					return;
				}else if(Long.bitCount(g[i]&~removed)==1
						&&((g[i]&~removed)|(g[i]&~covered))==(g[i]&~removed)){
					int j=Long.numberOfTrailingZeros(g[i]&~removed);
					mds(choosed|(1L<<j), removed|(1L<<i)|(1L<<j), covered
							|(1L<<j)|g[j]);
					return;
				}
			}
			if(k==-1||Long.bitCount(g[i]&~covered)>Long.bitCount(g[k]&~covered))
				k=i;
		}
		if(k==-1)
			return;

		mds(choosed|(1L<<k), removed|(1L<<k), covered|(1L<<k)|g[k]);
		mds(choosed, removed|(1L<<k), covered);
	}

	void println(String s){
		System.out.println(s);
	}

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

	public static void main(String[] args){
		Locale.setDefault(Locale.US);
		new P111C().run();
	}

}


import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;

import static java.lang.Math.*;
import static java.util.Arrays.*;

// Petya and Spiders
// 2011/9/3
public class P111C{
	Scanner sc=new Scanner(System.in);

	int INF=1<<28;

	int n, m;

	void run(){
		n=sc.nextInt();
		m=sc.nextInt();
		solve();
	}

	void solve(){
		if(n<m){
			int t=n;
			n=m;
			m=t;
		}
		int full=(1<<m)-1;
		int[][] dp=new int[1<<m][1<<m];
		int[][] tmp=new int[1<<m][1<<m];
		for(int i=0; i<1<<m; i++){
			fill(dp[i], INF);
		}
		for(int i=0; i<1<<m; i++){
			int b1=(i|(i>>1)|(i<<1))&full;
			int b2=i;
			dp[b1][b2]=Integer.bitCount(i);
		}
		for(int j=0; j<n-1; j++){
			for(int i=0; i<1<<m; i++){
				System.arraycopy(dp[i], 0, tmp[i], 0, 1<<m);
				fill(dp[i], INF);
			}

			for(int b1=0; b1<1<<m; b1++){
				for(int b2=0; b2<1<<m; b2++){
					for(int i=0; i<1<<m; i++){
						if((b1|i)!=full){
							continue;
						}
						int b=(i|(i>>1)|(i<<1))&full;
						dp[b2|b][i]=min(dp[b2|b][i],
								tmp[b1][b2]+Integer.bitCount(i));
					}
				}
			}
		}

		int min=INF;
		for(int i=0; i<1<<m; i++){
			min=min(min, dp[full][i]);
		}
		int ans=m*n-min;
		println(ans+"");
	}

	void println(String s){
		System.out.println(s);
	}

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


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

public class Main
{
	static final boolean _DEBUG = false;

	private static class MyScanner {
		BufferedReader br;
		StringTokenizer st;

		public MyScanner(BufferedReader _br) {
			br = _br;
		}

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

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

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

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

		String nextLine() {
			String str = "";
			try {
				str = br.readLine();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return str;
		}

	}

	static MyScanner   scan;
	static PrintWriter out;

	static int debugCount = 0;
	static void debug(String msg) {
		if (_DEBUG && debugCount < 200) {
			out.println(msg);
			out.flush();
			debugCount++;
		}
	}

    public static void main (String args[]) throws IOException {
//    	scan = new MyScanner(new BufferedReader(new FileReader("test.in")));
    	scan = new MyScanner(new BufferedReader(new InputStreamReader(System.in)));
    	out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
        Main inst = new Main();
        inst.execute();
        out.close();
    }

    int N, M, pow;
    int[] counts;
    int[][][] dp;

    void execute() {
    	N = scan.nextInt();
    	M = scan.nextInt();
    	if (N < M) {
    		int temp = N;
    		N = M;
    		M = temp;
    	}
    	pow = 1<<M;
    	counts = new int[pow];
    	dp = new int[N][pow][pow];
    	for (int[][] i : dp) {
    		for (int[] j : i) {
    			Arrays.fill(j, -1);
    		}
    	}
    	for (int i = 0; i < pow; i++) {
    		counts[i] = Integer.bitCount(i);
        	dp[0][i][0] = counts[i];
    	}
    	int spiders = Integer.MAX_VALUE;
    	for (int y = 0; y < N-1; y++) {
    		for (int i = 0; i < pow; i++) {
    			for (int j = 0; j < pow; j++) {
    				if (dp[y][i][j] == -1) {
    					continue;
    				}
    				for (int k = 0; k < pow; k++) {
    					if (((i|(i<<1)|(i>>1)|j|k)&(pow-1))==(pow-1)) {
    						int value = dp[y][i][j] + counts[k];
    						if (dp[y+1][k][i] == -1 || dp[y+1][k][i] > value) {
    							dp[y+1][k][i] = value;
    						}
    					}
    				}
    			}
    		}
    	}
//    	for (int i = 0; i < N; i++) {
//        	System.out.println(Arrays.deepToString(dp[i]));
//    	}
    	for (int i = 0; i < pow; i++) {
    		for (int j = 0; j < pow; j++) {
    			if (dp[N-1][i][j] != -1 && ((i|(i<<1)|(i>>1)|j)&(pow-1))==(pow-1)) {
    				spiders = Math.min(spiders, dp[N-1][i][j]);
//    				System.out.println(spiders+" "+i+" "+j);
    			}
    		}
    	}
    	out.println((N*M)-spiders);
    }
}


import java.util.*;

public class cf112e {
    static int n,m,s;
    static int[][][] memo;
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        m = in.nextInt();
        if(n > m) {
            int tmp = n;
            n = m;
            m = tmp;
        }
        s = (1<<n);
        memo = new int[s][s][m];
        for(int i=0; i<s; i++)
            for(int j=0; j<s; j++)
                Arrays.fill(memo[i][j], -1);
        int ret = go(0,0,0);
        System.out.println(n*m - ret);
    }
    static int go(int last, int trans, int r) {
        if(r==m) {
            if(trans == 0) return 0;
            return 100;
        }
        if(memo[last][trans][r] != -1) return memo[last][trans][r];
        int best = 100;
        for(int crnt = 0; crnt < s; crnt++) {
            if((trans & ~crnt) != 0) continue; //certain ones have to be here
            for(int pass = 0; pass < s; pass++) {
                int tmp = ((1<<n)-1) & ~last;   //move back the ones you can
                if((pass & ~tmp) != 0) continue; //certain ones have to move on
                tmp = tmp & ~pass; //find which ones stay
                boolean fail = false;
                for(int k=0; k<n; k++) //make sure that the ones that stay
                    if(isSet(tmp,k) && !(isSet(crnt,k-1) || isSet(crnt,k) || isSet(crnt,k+1)))
                        fail = true;
                if(fail) continue;
                best = Math.min(best, Integer.bitCount(crnt) + go(crnt,pass,r+1));
            }
        }
        return memo[last][trans][r] = best;
    }
    static boolean isSet(int x, int p) {
        if(p < 0 || p >= n) return false;
        return (x & (1<<p)) != 0;
    }
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

/**
 * Author -
 * User: kansal
 * Date: 9/3/11
 * Time: 5:28 PM
 */
public class CF85E {
    public static void main(String[] args) {
        reader = new BufferedReader(new InputStreamReader(System.in));

        int height = nextInt(), width = nextInt();
        if (width > height) {
            int t = width;
            width = height;
            height = t;
        }

        final int INF = height * width + 10;
        int[][][] dp = new int[height + 1][1 << width][1 << width];
        for (int[][] ints : dp) {
            for (int[] anInt : ints) {
                Arrays.fill(anInt, INF);
            }
        }

        dp[0][0][0] = 0;
        for(int r = 0; r < height; ++r) {
            for(int uncovered = 0; uncovered < (1 << width); ++uncovered) {
                for(int mask = 0; mask < (1 << width); ++mask) {
                    if (dp[r][uncovered][mask] == INF) {
                        continue;
                    }
                    for(int curMask = uncovered; curMask < (1 << width); curMask = (curMask + 1) | uncovered) {
                        int curUncovered = (1 << width) - 1;
                        for(int i = 0; i < width; ++i) {
                            if (hasBit(mask, i) || hasBit(curMask, i)) {
                                curUncovered &= ~(1 << i);
                            }
                            if (i > 0 && hasBit(curMask, i-1)) {
                                curUncovered &= ~(1 << i);
                            }
                            if (i < width-1 && hasBit(curMask, i+1)) {
                                curUncovered &= ~(1 << i);
                            }
                        }
                        dp[r+1][curUncovered][curMask] = Math.min(dp[r+1][curUncovered][curMask], dp[r][uncovered][mask] + Integer.bitCount(curMask));
                    }
                }
            }
        }

        int res = INF;
        for(int x: dp[height][0]) res = Math.min(res, x);

        System.out.println(height * width - res);
    }

    private static boolean hasBit(int mask, int bit) {
        return (((mask >> bit) & 1) == 1);
    }

    public static BufferedReader reader;

    public static StringTokenizer tokenizer = null;

    static String nextToken() {
        while (tokenizer == null || !tokenizer.hasMoreTokens()) {
            try {
                tokenizer = new StringTokenizer(reader.readLine());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return tokenizer.nextToken();
    }

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

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

    static public String next() {
        return nextToken();
    }

    static public String nextLine() {
        try {
            return reader.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}


import static java.lang.Math.*;
import static java.lang.System.currentTimeMillis;
import static java.lang.System.exit;
import static java.lang.System.arraycopy;
import static java.util.Arrays.sort;
import static java.util.Arrays.binarySearch;
import static java.util.Arrays.fill;
import java.util.*;
import java.io.*;

public class Main {

	public static void main(String[] args) throws IOException {
		try {
			if (new File("input.txt").exists())
				System.setIn(new FileInputStream("input.txt"));
		} catch (SecurityException e) {
		}
		new Thread(null, new Runnable() {
			public void run() {
				try {
					new Main().run();
				} catch (Throwable e) {
					e.printStackTrace();
					exit(999);
				}
			}
		}, "1", 1 << 23).start();
	}

	BufferedReader in;
	PrintWriter out;
	StringTokenizer st = new StringTokenizer("");

	int n, m;
	int dp[][][];
	int MV = Integer.MAX_VALUE >> 1;
	int ans = MV;

	private void run() throws IOException {
		in = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);

		n = nextInt();
		m = nextInt();
		if(n < m){ int d = n; n = m; m = d; }
		int M = 1 << m;
		dp = new int[n][M][M];
		for(int a[][] : dp)
			for(int b[] : a)
				fill(b, MV);

//		for(int i = 0 ; i < M; i++){
//			int next = (( i | (i << 1) | (i >> 1) ) & (M - 1));
//			if(  next!= (M -1))
//				continue;
//			if(n > 1)
//				dp[0][next][0] = Integer.bitCount(i);
//			else
//				ans = min(ans, Integer.bitCount(i));
//		}
		dp[0][0][0] = 0;

		for(int i = 0; i < n; i++)
			for(int m1 = 0; m1 < M; m1++)
				for(int m2 = 0; m2 < M; m2++){
					if(dp[i][m1][m2] == MV)
						continue;
					for(int nm1 = 0; nm1 < M; nm1++)
						for(int nm2 = 0; nm2 < M; nm2++){
							int res1 = m1 | (nm1) | (nm1 << 1) | (nm1 >> 1) | (nm2);
							res1 &= (M - 1);

							if(res1 != (M - 1))
								continue;

							int res2 = m2 | (nm1) | (nm2 << 1) | (nm2 >> 1) | (nm2);
							res2 &= (M - 1);

//							if(i == 2 && m1 == 3 && m2 == 2 && nm1 == 0 && nm2 == 0){
//								System.err.println("kek");
//								System.err.println(dp[i][m1][m2]);
//								System.err.println(res1 + " | " + res2);
//								System.err.println(M);
//							}

							int next1 = res2 & (M - 1);
							int next2 = nm2 & ( M - 1);
							int over = Integer.bitCount(nm1) + Integer.bitCount(nm2);

							if(i < n - 1)
								dp[i+1][next1][next2] = min(dp[i + 1][next1][next2], dp[i][m1][m2] + over);
							else
								if((res1 & (M - 1)) == (M - 1)){
									ans = min(dp[i][m1][m2] + over, ans);
								}
						}

				}
//		System.err.println(ans);
		out.println(n * m - ans);

		in.close();
		out.close();
	}
	String nextToken() throws IOException {
		while (!st.hasMoreTokens())
			st = new StringTokenizer(in.readLine());
		return st.nextToken();
	}
	int nextInt() throws IOException {
		return Integer.parseInt(nextToken());
	}
	long nextLong() throws IOException {
		return Long.parseLong(nextToken());
	}
	double nextDouble() throws IOException {
		return Double.parseDouble(nextToken());
	}
	String nextLine() throws IOException {
		st = new StringTokenizer("");
		return in.readLine();
	}
	boolean EOF() throws IOException {
		while (!st.hasMoreTokens()) {
			String s = in.readLine();
			if (s == null)
				return true;
			st = new StringTokenizer(s);
		}
		return false;
	}
}


/*************************************************************************
    > File Name: cf111c.java
    > Author: Yuchen Wang
    > Mail: wyc8094@gmail.com
    > Created Time: Sat Feb 11 16:51:01 2017
 ************************************************************************/

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

public class cf111c
{
	public static int n,m,maxm;
	public static int[][][] dp;
	public static int[] s;

	public static int cal(int cur)
	{
		int res = 0;
		while(cur>0){
			res ++;
			cur = cur&(cur-1);
		}
		return res;
	}

	public static boolean check(int a,int b,int c)
	{
		int res = (maxm-1) & (b | (b<<1) | (b>>1) | a | c);
		if(res == maxm-1)return true;
		else return false;
	}

	public static void main(String[] argv)
	{
		Scanner in = new Scanner(System.in);

		n = in.nextInt();
		m = in.nextInt();
		if(n<m){
			int t = m;
			m = n;
			n = t;
		}

		maxm = 1<<m;
		int i,j,k,l;
		dp = new int[n+1][1<<m][1<<m];
		s = new int[1<<m];

		for(i=0;i<n+1;i++){
			for(j=0;j<maxm;j++){
				Arrays.fill(dp[i][j],100);
			}
		}

		for(i=0;i<maxm;i++){
			s[i] = cal(i);
			dp[0][0][i] = 0;
		}

		for(i=1;i<=n;i++){
			for(j=0;j<maxm;j++){
				for(k=0;k<maxm;k++){
					for(l=0;l<maxm;l++){
						if(dp[i-1][k][l]!=100 && check(k,l,j)){
							dp[i][l][j] = Math.min(dp[i-1][k][l]+s[l],dp[i][l][j]);
						}
					}
				}
			}
		}

		int ans = 100;
		for(i=0;i<maxm;i++)
			ans = Math.min(dp[n][i][0],ans);

		System.out.println(n*m-ans);
		return;
	}
}


import java.util.Arrays;

/**
 * Created by IntelliJ IDEA.
 * User: piyushd
 * Date: 3/26/11
 * Time: 10:53 PM
 * To change this template use File | Settings | File Templates.
 */
public class TaskC {

    final  int INF = 123456;
    int[][][] memo;
    int N, M;

    int solve(int row, int prevFreeMask, int curStayMask) {
        if(row == N) return (curStayMask == 0) ? 0 : -INF;
        if(memo[row][prevFreeMask][curStayMask] != -1) return memo[row][prevFreeMask][curStayMask];

        int res = 0;
        for(int mask = 0; mask < (1<<M); mask++) {
            if((mask & curStayMask) == curStayMask) {
                int freeCellsMask = (1<<M) - 1 - mask;
                int toMoveMask = freeCellsMask;

                for(int i = 0; i < M; i++) {
                    if((toMoveMask & (1<<i)) > 0) {
                        if(i > 0) {
                            if((mask & (1<<(i - 1))) > 0) {
                                toMoveMask -= (1<<i);
                                continue;
                            }
                        }

                        if(i < M - 1) {
                            if((mask & (1<<(i + 1))) > 0) {
                                toMoveMask -= (1<<i);
                                continue;
                            }
                        }
                    }
                }

                if (row > 0) {
                    for (int prevFillMask = toMoveMask; prevFillMask > 0; prevFillMask = (prevFillMask - 1) & toMoveMask) {
                        int bc1 = Integer.bitCount(freeCellsMask);
                        int bc2 = Integer.bitCount(prevFreeMask & prevFillMask);
                        res = Math.max(res, bc1 - bc2 + solve(row + 1, freeCellsMask, toMoveMask ^ prevFillMask));
                    }
                }

                res = Math.max(res, Integer.bitCount(freeCellsMask) + solve(row + 1, freeCellsMask, toMoveMask));
            }
        }

        return memo[row][prevFreeMask][curStayMask] = res;
    }

    void run() {
        N = nextInt();
        M = nextInt();
        if(M > N) {
            int temp = M;
            M = N;
            N = temp;
        }

        this.memo = new int[N + 1][1<<M][1<<M];
        for(int[][] g : memo) for(int[] f : g) Arrays.fill(f, -1);

        System.out.println(solve(0, 0, 0));
    }

    int nextInt(){
        try{
            int c = System.in.read();
            if(c == -1) return c;
            while(c != '-' && (c < '0' || '9' < c)){
                c = System.in.read();
                if(c == -1) return c;
            }
            if(c == '-') return -nextInt();
            int res = 0;
            do{
                res *= 10;
                res += c - '0';
                c = System.in.read();
            }while('0' <= c && c <= '9');
            return res;
        }catch(Exception e){
            return -1;
        }
    }

    long nextLong(){
        try{
            int c = System.in.read();
            if(c == -1) return -1;
            while(c != '-' && (c < '0' || '9' < c)){
                c = System.in.read();
                if(c == -1) return -1;
            }
            if(c == '-') return -nextLong();
            long res = 0;
            do{
                res *= 10;
                res += c-'0';
                c = System.in.read();
            }while('0' <= c && c <= '9');
            return res;
        }catch(Exception e){
            return -1;
        }
    }

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

    String next(){
        try{
            StringBuilder res = new StringBuilder("");
            int c = System.in.read();
            while(Character.isWhitespace(c))
                c = System.in.read();
            do{
                res.append((char)c);
            }while(!Character.isWhitespace(c=System.in.read()));
            return res.toString();
        }catch(Exception e){
            return null;
        }
    }

    String nextLine(){
        try{
            StringBuilder res = new StringBuilder("");
            int c = System.in.read();
            while(c == '\r' || c == '\n')
                c = System.in.read();
            do{
                res.append((char)c);
                c = System.in.read();
            }while(c != '\r' && c != '\n');
            return res.toString();
        }catch(Exception e){
            return null;
        }
    }

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


import java.util.ArrayList;
import java.util.List;
import java.util.InputMismatchException;
import java.math.BigInteger;
import java.util.Iterator;
import java.io.*;
import java.util.Comparator;
import java.util.Arrays;
import java.util.Collection;

/**
 * Generated by Contest helper plug-in
 * Actual solution is at the bottom
 */
public class Main {
	public static void main(String[] args) {
		InputReader in = new StreamInputReader(System.in);
		PrintWriter out = new PrintWriter(System.out);
		run(in, out);
	}

	public static void run(InputReader in, PrintWriter out) {
		Solver solver = new TaskC();
		solver.solve(1, in, out);
		Exit.exit(in, out);
	}
}

abstract class InputReader {
	private boolean finished = false;

	public abstract int read();

	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 String readString() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuffer res = new StringBuffer();
		do {
			res.appendCodePoint(c);
			c = read();
		} while (!isSpaceChar(c));
		return res.toString();
	}

	private boolean isSpaceChar(int c) {
		return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
	}

	public void setFinished(boolean finished) {
		this.finished = finished;
	}

	public abstract void close();
}

class StreamInputReader extends InputReader {
	private InputStream stream;
	private byte[] buf = new byte[1024];
	private int curChar, numChars;

	public StreamInputReader(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 void close() {
		try {
			stream.close();
		} catch (IOException ignored) {
		}
	}
}

class Exit {
	private Exit() {
	}

	public static void exit(InputReader in, PrintWriter out) {
		in.setFinished(true);
		in.close();
		out.close();
	}
}

interface Solver {
	public void solve(int testNumber, InputReader in, PrintWriter out);
}

class ArrayUtils {

	public static void fill(int[][] array, int value) {
		for (int[] row : array)
			Arrays.fill(row, value);
	}

	public static void fill(int[][][] array, int value) {
		for (int[][] subArray : array)
			fill(subArray, value);
	}

	}

class TaskC implements Solver {
	public void solve(int testNumber, InputReader in, PrintWriter out) {
		int rowCount = in.readInt();
		int columnCount = in.readInt();
		out.println(rowCount * columnCount - go(Math.min(rowCount, columnCount), Math.max(rowCount, columnCount)));
	}

	private int go(int rowCount, int columnCount) {
		int[][][] result = new int[columnCount][rowCount][1 << (2 * rowCount)];
		ArrayUtils.fill(result, -1);
		return go(0, 0, (1 << rowCount) - 1, result);
	}

	private int go(int column, int row, int mask, int[][][] result) {
		if (column == result.length)
			return (mask == 0 ? 0 : Integer.MAX_VALUE / 2);
		int length = result[column].length;
		if (row == length)
			return go(column + 1, 0, mask, result);
		if (result[column][row][mask] != -1)
			return result[column][row][mask];
		result[column][row][mask] = Integer.MAX_VALUE / 2;
		if ((mask >> (2 * length - 1) & 1) == 0)
			result[column][row][mask] = go(column, row + 1, mask * 2 + (column == result.length - 1 ? 0 : 1), result);
		int newMask = mask;
		newMask &= ~(1 << (length - 1));
		if (row != 0)
			newMask &= ~(1 << length);
		if (row != length - 1)
			newMask &= ~(1 << (length - 2));
		newMask *= 2;
		newMask &= (1 << (2 * length)) - 1;
		return result[column][row][mask] = Math.min(result[column][row][mask], 1 + go(column, row + 1, newMask, result));
	}
}