Problem:
Code Art Online

G: コードアートオンライン

コードアートオンライン（CAO）は，様々な問題をプログラミングによって解くことにより，冒険を進めて行くオンラインRPGである．
CAOは，世界初のバーチャルリアリティ空間を実現したゲームであったこともあり，大人気の内に完売し，ゲームを購入したユーザ達はこの世界を楽しむはずであった．
しかし，ゲームにダイブしたプレイヤー達は，ゲームマスターから恐るべき託宣を聞かされる．

「君たちプレイヤーの内の誰かが，ラストダンジョンのラストプロブレムを解かない限り，この仮想空間から抜け出すことはできない．そして，この世界での，WAやTLE・REは，現実世界での死を意味する．心して問題にとりかかってほしい．」

あなたも，CAOのプレイヤーの内の1人で，このゲームをクリアして現実世界に戻るために，ゲーム攻略に全力を尽くしている．
ある日，あなたは次のような問題に直面することとなった．

今回，新たなダンジョンを攻略するために，n人のメンバーでパーティが組まれた．
あなたもこのパーティの内の1人である．
今から攻略するダンジョンに突入するためには，崖から見える穴を通過しなくてはならない．
無事に穴を通過できれば，ダンジョンに突入できるが，穴に突入できず他の部分に触れてしまうと，死が待っている．
さらに，1つの穴に誰かが通ると，その穴は閉じてしまうため，1人1人別々の穴に入らなければならない．

穴や人は，二次元平面上で考えることとする．
穴の形は，図G-1のような，大小様々な円である．入力では，半径の長さが与えられる．

図G-1: 穴の形

人の形は，図G-2のように人の断面が多角形で与えられる（凸とは限らない）．
入力では，多角形の形を表すために，頂点が反時計まわりで与えられる．
多角形の任意の三点は，1直線上に並ばないと仮定してよい．
さらに，頂点を構成する目的以外で，多角形の線分同士が交差することはないものとする．
穴に通すために，自由に回転してよい（ただし，z軸方向への回転は禁止する）．
人を表す多角形の頂点が，穴の円周上にある場合でも，穴を通過できるものとする．

図G-2: 人の形

パーティの中で最もアルゴリズムスキルが高いあなたは，みんなで無事に穴を通過できるかどうかの判定問題を解くことにした．
もし，無事に通過できるなら，どの人がどの穴を通過すればいいのか表示せよ．

※今回のコンテストで死ぬことはありませんが，間違ったら死ぬつもりで解いてください．

Input

1行目に，穴の数を表す整数n (1 <= n <= 100)と，パーティの人数を表す整数m (1 <= m <= n)がスペース区切りで入力される．

次の行に，穴の半径を表す整数ri (1 <= ri <= 1000)がスペース区切りでn個入力される．
これらの穴は，入力された順番に，1番の穴, 2番の穴, ..., n番の穴と数えることとする．

続いて，m人の人の形の情報が入力される．
1人の情報は，まず1行目に多角形の頂点数p (3 <= p <= 100)が入力される．
続くp行には，多角形の頂点の座標が反時計周りで与えられる．
各行には，1つの頂点を表す整数xi, yi (-1000 <= xi, yi <= 1000)がスペース区切りで入力される．
人は，入力された順番に，1番の人, 2番の人, ..., m番の人と数えることとする．

Output

i番(1 <= i <= m)の人が，何番の穴に入ればいいかを出力せよ．
i行目には，i番の人が通るべき穴の番号を出力すること．

もし，複数の通り方がある場合，辞書順で一番小さくなる通り方を出力すること．
2つの数列A = {a1, a2, ..., am}とB = {b1, b2, ..., bm}があったとき，AがBより辞書順で小さいとは，aiがbiと異なるような最初のiについて，aiがbiより小さいときのことを言う．

通り方が1つも見つからない場合は，"NG"と1行出力すること．
最後に改行を出力するのを忘れないこと．

Sample Input 1

3 3
25 100 10
8
-10 0
-2 2
0 10
2 2
10 0
2 -2
0 -10
-2 -2
4
30 0
50 0
50 40
30 40
3
30 -10
45 -70
60 -10

Sample Output 1

3
1
2

Sample Input 2

4 3
25 15 15 30
5
0 0
10 0
20 10
0 20
-20 10
3
20 0
40 0
30 10
3
-50 0
-30 0
-40 10

Sample Output 2

1
2
3

Sample Input 3

2 2
1 30
4
0 0
10 0
10 10
0 10
3
5 5
20 20
5 20

Sample Output 3

NG

Solution in C (judge verdict: Accepted)

// AOJ 2423 Code Art Online
// 2018.4.8 bal4u

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

#define MAX 210
short hi[MAX], to[MAX][MAX];
char seen[MAX];
int  match[MAX];

int bpm(int u);
int bipartiteMatching(int m, int n)
{
	int u, max;

	memset(match, -1, (m+n)*sizeof(int));
	max = 0;
	for (u = 0; u < m; u++) {
		memset(seen, 0, m+n);
		if (bpm(u)) max++;
	}
	return max;
}

int bpm(int u)
{
	int i, v;

	for (i = 0; i < hi[u]; i++) {
		v = to[u][i];
		if (seen[v]) continue;
		seen[v] = 1;
		if (match[v] < 0 || bpm(match[v])) {
			match[u] = v, match[v] = u;
			return 1;
		}
	}
	return 0;
}

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

int    rn[102];
double rm[102];
char   rel[102][102];
char   assign[102], f[102];

typedef struct { double x, y; } PP;
PP p[102];

#define EPS 1e-6
#define EQ(a,b)  (fabs((a)-(b))<EPS)

double smallestCircle(int n)
{
	int  k, i, t;
	PP a = { 50, 50 };
	double move, max, d;

	move = 0.5;
	while (move > 1e-12) {
		for (t = 0; t < 100; t++) {
			max = 0;
			for (i = 0; i < n; i++) {
				if ((d = hypot(a.x-p[i].x, a.y-p[i].y)) > max) max = d, k = i;
			}
			a.x += (p[k].x - a.x)*move;
			a.y += (p[k].y - a.y)*move;
		}
		move /= 2;
	}
	return max;
}

int main()
{
	int n, m, i, j, k, l;

	n = in(), m = in();
	for (i = 0; i < n; i++) rn[i] = in();
	for (i = 0; i < m; i++) {
		k = in();
		for (j = 0; j < k; j++) p[j].x = in(), p[j].y = in();
		rm[i] = smallestCircle(k);
	}

	for (i = 0; i < m; i++) for (j = 0; j < n; j++) {
		if (EQ(rm[i], rn[j]) || rm[i] <= rn[j]) {
			rel[i][j] = 1;
			to[i][hi[i]++] = m+j;
		}
	}

	if (bipartiteMatching(m, n) != m) puts("NG");
	else {
		for (i = 0; i < m; i++) {
			for (j = 0; j < n; j++) {
				if (!f[j] && rel[i][j]) {
					for (k = i+1; k < m; k++) hi[k] = 0;
					f[j] = 1;
					hi[i] = 1, to[i][0] = m+j;
					for (k = i+1; k < m; k++) {
						for (l = 0; l < n; l++) {
							if (rel[k][l] && !f[l]) to[k][hi[k]++] = m+l;
						}
						if (hi[k] == 0) continue;
					}

					if (bipartiteMatching(m, n) == m) {
						assign[i] = 1+j;
						break;
					}
					f[j] = 0;
				}
			}
		}
		for (i = 0; i < m; i++) printf("%d\n", assign[i]);
	}
	return 0;
}