Problem:
真っ暗な部屋

目を覚ますと、A君は真っ暗な部屋の中にいた。
どうやらA君は N 個の部屋から構成されたダンジョンに迷い込んでしまったようだ。
あなたはA君がどの部屋に迷い込んだのかを知ることはできなかったが、幸いにもダンジョンのマップを手に入れることができた。
A君の進むべき道を示し明るい部屋に導こう。

N 個の部屋のうち M 個の部屋が真っ暗な部屋であり、それぞれ D_1, D_2, ..., D_M 番目の部屋が真っ暗な部屋であることが分かっている。
また、全ての部屋からちょうど K 本の一方通行の道が順に並んでおり、i 番目の部屋から出る道はそれぞれ
v_{i,1}, v_{i,2}, ..., v_{i,K} 番目の部屋に繋がっている。
あなたは、A君に対し今いる部屋から a_1, a_2, ..., a_l 番目の道を順に進ませることができる。
ただし、A君は明るい部屋に到達したらそれ以降の指示は無視する。
あなたは、指示の前後においてA君が今いる部屋の情報を知ることはできないため、A君がどの部屋にいたとしても明るい部屋に辿り着けるような指示列を伝えなければならない。

そのような指示のうち、最も短いものの長さを答えよ。

Constraints

2 ≤ N ≤ 100

1 ≤ M ≤ min(16, N − 1)

1 ≤ K ≤ N

1 ≤ D_i ≤ N

D_i は全て異なる

1 ≤ v_{i, j} ≤ N

全ての暗い部屋は少なくとも1つの明るい部屋に到達可能である

Input Format

入力は以下の形式で標準入力から与えられる。

N M K
D_1 D_2 ... D_M
v_{1,1} v_{1,2} ... v_{1,K}
v_{2,1} v_{2,2} ... v_{2,K}
...
v_{N,1} v_{N,2} ... v_{N,K}

Output Format

答えを一行に出力せよ。

Sample Input 1

4 2 2
1 2
2 4
3 1
4 2
1 3

Sample Output 1

2

1, 1 という指示を出すと

A君の初期位置が部屋1である場合、2つ目の移動で部屋3に到達する

A君の初期位置が部屋2である場合、1つ目の移動で部屋3に到達する

Sample Input 2

3 2 2
1 2
2 3
1 2
2 1

Sample Output 2

3

2, 1, 2 という指示を出すと

A君の初期位置が部屋1である場合、1つ目の移動で部屋3に到達する

A君の初期位置が部屋2である場合、3つ目の移動で部屋3に到達する

Sample Input 3

6 3 3
1 2 3
4 1 1
2 5 2
3 3 6
4 4 4
5 5 5
6 6 6

Sample Output 3

3

非連結であるケースや、自己辺、多重辺があるケースに気をつけよう

Solution in C (judge verdict: Accepted)

// AOJ 2709 Dark Room
// 2018.3.31 bal4u

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

//#define getchar_unlocked()  getchar()
int in()
{
	int n = 0, c = getchar_unlocked();
	do n = 10*n + (c & 0xf), c = getchar_unlocked(); while (c >= '0');
	return n;
}

#define INF 0x10101010
#define QMAX 100000
int q[QMAX]; int top, end;
int d[18], r[102];
int v[102][102];
int dist[1<<16];

int main()
{
	int N, M, K, i, j, k, s, e, t;

	N = in(), M = in(), K = in();
	memset(r, -1, sizeof(r));
	for (i = 0; i < M; i++) d[i] = in()-1, r[d[i]] = 1<<i;
	for (i = 0; i < N; i++) for (j = 0; j < K; j++) v[i][j] = in()-1;

	memset(dist, INF, sizeof(dist));
	q[0] = s =(1<<M)-1, dist[s] = 0;
	top = 0, end = 1;
	while (top != end) {
		s = q[top++];

		if ((t=dist[s]) == INF) continue;
		for (i = 0; i < K; i++) {
			e = 0;
			for (j = 0; j < M; j++) if ((s>>j)&1) {
				k = v[d[j]][i];
				if (r[k] >= 0) e |= r[k];
			}
			if (dist[e] > t+1) dist[e] = t+1, q[end++] = e;
		}
	}
	printf("%d\n", dist[0]);
	return 0;
}