Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], skipTags: ["script","noscript","style","textarea","code"], processEscapes: true }});

問題文

$1,2,...,N$ を並べ替えた順列がある。2つの異なる数字 $i$, $j$ を選んで入れ替えることを繰り返してソートされた状態( $1,2,...,N$ の順番に並んだ状態)にしたい。
数字 $i$, $j$ を入れ替える度にコストが $c_{i,j}$ 必要になる。

順列 $p$ に対して、 $p$ をソートするのに必要な最小コストを $f(p)$ とする。
$f(p)$ のとりうる最大値を求めよ。

入力

入力は以下のフォーマットに従う。与えられる数は全て整数である。

$N$
$c_{1,1}$ $c_{1,2}$ $...$ $c_{1,N}$
$c_{2,1}$ $c_{2,2}$ $...$ $c_{2,N}$
$...$
$c_{N,1}$ $c_{N,2}$ $...$ $c_{N,N}$

制約

$2 \leq N \leq 8$

$0 \leq c_{i,j} \leq 10^5$

$c_{i,j} = c_{j,i}$

$c_{i,i} = 0$

出力

最大値を1行に出力せよ。

Sample Input 1

3
0 1 3
1 0 8
3 8 0

Output for the Sample Input 1

5

もっとも必要コストが大きい順列は$\{1,3,2\}$で、

1,2を入れ替えて$\{2,3,1\}$とする。

1,3を入れ替えて$\{2,1,3\}$とする。

1,2を入れ替えて$\{1,2,3\}$とする。

以上の操作によりコスト5でソートでき、またこれが最善であることが証明できる。
他の順列もコスト5以下でソートできることを示すことができる。

Solution in C (judge verdict: Memory Limit Exceeded)

// AOJ 2361: Sort
// 2017.12.18 bal4u@uu

#include <stdio.h>
#include <string.h>

#define QSIZE 8000000

#define PARENT(i) ((i)>>1)
#define LEFT(i)   ((i)<<1)
#define RIGHT(i)  (((i)<<1)+1)

typedef struct { char s[8]; int t; } QUE;
QUE que[QSIZE+5];
int qsize;

int N, N1, N2, N3;

void max_heapify(int i)
{
	int l, r, max;
	QUE qt;
	l = LEFT(i), r = RIGHT(i);
	if (l < qsize && que[l].t > que[i].t) max = l; else max = i;
	if (r < qsize && que[r].t > que[max].t) max = r;
	if (max != i) {
		qt = que[i], que[i] = que[max], que[max] = qt;
		max_heapify(max);
	}
}

void deq()
{
//	if (qsize == 0) return 0;
//	*t = que[0].t;
	que[0] = que[--qsize];
	max_heapify(0);
}

void enq(int t, char *s)
{
	int i, max;
	QUE qt;

	i = qsize++;
	que[i].t = t, memcpy(que[i].s, s, N);
	while (i > 0 && que[max = PARENT(i)].t < que[i].t) {
		qt = que[i]; que[i] = que[max], que[max] = qt;
		i = max;
	}
}

#define HSIZ 100019
typedef struct { char s[8]; int t; } HASH;
HASH hash[HSIZ+2], *hashend = hash + HSIZ;

int lookup(char *s, int t)
{
	HASH *tp;

	tp = hash + ((s[0] << N3) + (s[N>>1] << N2) + (s[N-1])*101 + N1) % HSIZ;

	while (tp->t) {
		if (!memcmp(tp->s, s, N)) {
			if (tp->t > t) { tp->t = t; return 1; }
			return 0;
		}
		if (++tp == hashend) tp = hash;
	}
	memcpy(tp->s, s, N), tp->t = t;
	return 1;
}

int c[8][8];
char start[8] = {0,1,2,3,4,5,6,7};

int main()
{
	int i, j, t, cost, ans;
	char s[10], a;

	scanf("%d", &N); N3 = N << 3, N2 = (N>>1) << 3, N1 = N*103;
	for (i = 0; i < N; i++) for (j = 0; j < N; j++) scanf("%d", &c[i][j]);

	ans = 0;
	qsize = 0, enq(0, start);
	while (qsize) {
		t = que[0].t, memcpy(s, que[0].s, N), deq();

		for (i = 0; i < N; i++) for (j = i+1; j < N; j++) {
			a = s[i], s[i] = s[j], s[j] = a;
			cost = t + c[s[i]][s[j]];
			if (lookup(s, cost)) enq(cost, s);
			a = s[i], s[i] = s[j], s[j] = a;
		}
	}

	ans = 0;
	for (i = 0; i < HSIZ; i++) if (hash[i].t > ans) ans = hash[i].t;
	printf("%d\n", ans);
	return 0;
}