import java.util.*;

// https://en.wikipedia.org/wiki/Bron–Kerbosch_algorithm
public class BronKerbosh {

	public static int BronKerbosch(long[] g, long cur, long allowed, long forbidden, int[] weights) {
		if (allowed == 0 && forbidden == 0) {
			int res = 0;
			for (int u = Long.numberOfTrailingZeros(cur); u < g.length; u += Long.numberOfTrailingZeros(cur >> (u + 1)) + 1)
				res += weights[u];
			return res;
		}
		if (allowed == 0)
			return -1;
		int res = -1;
		int pivot = Long.numberOfTrailingZeros(allowed | forbidden);
		long z = allowed & ~g[pivot];
		for (int u = Long.numberOfTrailingZeros(z); u < g.length; u += Long.numberOfTrailingZeros(z >> (u + 1)) + 1) {
			res = Math.max(res, BronKerbosch(g, cur | (1L << u), allowed & g[u], forbidden & g[u], weights));
			allowed ^= 1L << u;
			forbidden |= 1L << u;
		}
		return res;
	}

	// random test
	public static void main(String[] args) {
		Random rnd = new Random(1);
		for (int step = 0; step < 1000; step++) {
			int n = rnd.nextInt(16) + 1;
			long[] g = new long[n];
			int[] weights = new int[n];
			for (int i = 0; i < n; i++)
				weights[i] = rnd.nextInt(1000);
			for (int i = 0; i < n; i++)
				for (int j = 0; j < i; j++)
					if (rnd.nextBoolean()) {
						g[i] |= 1L << j;
						g[j] |= 1L << i;
					}
			int res1 = BronKerbosch(g, 0, (1L << n) - 1, 0, weights);
			int res2 = maxCliqueSlow(g, weights);
			if (res1 != res2)
				throw new RuntimeException();
		}
	}

	static int maxCliqueSlow(long[] g, int[] weights) {
		int res = 0;
		int n = g.length;
		for (int set = 0; set < 1 << n; set++) {
			boolean ok = true;
			for (int i = 0; i < n; i++)
				for (int j = 0; j < i; j++)
					ok &= (set & (1 << i)) == 0 || (set & (1 << j)) == 0 || (g[i] & (1L << j)) != 0;
			if (ok) {
				int cur = 0;
				for (int i = 0; i < n; i++)
					if ((set & (1 << i)) != 0)
						cur += weights[i];
				res = Math.max(res, cur);
			}
		}
		return res;
	}
}
