Problem:
アルゴリズム検定試験

あなたはイズア地区におけるアルゴリズム検定試験を運営しており、運営費を最小にしたいと考えています。運営費は、会場使用料、バスの使用料、移動補助金の総和です。

今年は N 人の受験者登録があり、それぞれ ci 人まで受け入れ可能な M 個の会場を確保しました。あなたは各受験者を必ずどこかの会場に割り当てなければなりません。1 人以上割り当てた会場については、人数にかかわらず fi 円の会場使用料を支払う必要があります。

イズア地区は図に示すように東西方向と南北方向に 1 km 間隔で道が走っており、受験者の家と会場は交差点上にあると考えます。各受験者は家から会場まで道に沿って徒歩で移動できます。また、この検定試験では、1 人以上受験者を受け入れる各会場につき 1 台のシャトルバスが運行されるので、受験者はバスを利用することもできます。ただし、自分が受験する会場行きのバスにしか乗れません。

各シャトルバスは、会場からの東西方向の距離と南北方向の距離の和が D 以内のすべての交差点に停車します（図は D = 3 の場合）。バスの使用料は D に比例し、D が 1 km 増えると B 円上がります。つまり、シャトルバスを運行するには 1 会場あたり D × B 円の費用を支払う必要があります。なお、D 及び B はすべての会場で共通の値を用います。

移動補助金とは、各受験者に必要な最低限の徒歩での移動に対して運営者が受験者に支払う費用で、1 km について 1 円を払う必要があります。

あなたは受験者の家と会場の位置、会場の受け入れ可能人数と使用料、D が 1 km 増えたときに加算される料金 B の情報を入力データとして持っており、各受験者への会場割り当てと D を決定することができます（ただし、D は 0 以上の整数)。このとき、運営費の最小値を求めてください。

入力

入力は複数のデータセットからなる。入力の終わりはゼロ３つの行で示される。各データセットは以下の形式で与えられる。

N M B
ax1 ay1
ax2 ay2
:
axN ayN
bx1 by1 c1 f1
bx2 by2 c2 f2
:
bxM byM cM fM

1 行目は３つの整数からなる。N (1 ≤ N ≤ 100) は受験者の人数、M (1 ≤ M ≤ 5) は会場数である。B (0 ≤ B ≤ 1000) はシャトルバスを運行する際に、Dが 1 km 増えたときに加算される料金である。続く N 行に各受験者の家の座標が与えられる。axi, ayi (-1000 ≤ axi, ayi ≤ 1000) はそれぞれ受験者 i の家の x 座標と y 座標を示す。続く M 行に各会場の情報が与えられる。bxi, byi (-1000 ≤ bxi, byi ≤ 1000) はそれぞれ会場 i の x 座標と y 座標を示す。ci(1 ≤ ci ≤ 100) は会場 i の受け入れ可能人数、fi (0 ≤ fi ≤ 100000) は会場 i の使用料を示す。ただし、c1 からcM までの合計は N 以上である。

入力は以下の条件を満たすと考えてよい。

使用する会場を決めたとき、D = i におけるそれらの会場への受験者の割り当て方のうち移動補助金が最小となるときの金額を F(i) とする。このとき、F(i+2) - F(i+1) ≥ F(i+1)-F(i) が成立する。

データセットの数は 10 を超えない。

出力

データセットごとに試験の運営費の最小値を 1 行に出力する。

入出力例

入力例

1 1 1
0 0
0 0 1 0
1 1 0
0 0
-3 0 2 3
1 3 1
0 0
-3 0 2 3
0 -5 2 0
4 0 2 1
4 3 1
0 0
0 0
0 0
0 0
-3 0 2 3
0 -5 2 0
4 0 2 1
6 3 1
0 0
0 0
0 0
0 0
0 0
0 0
-3 0 2 3
0 -5 2 0
4 0 2 1
6 3 2
0 0
0 0
0 0
0 0
0 0
0 0
-3 0 2 3
0 -5 2 0
4 0 2 1
10 5 1
0 0
2 0
4 0
8 0
100 0
100 0
100 0
100 0
100 0
100 0
-3 0 1 0
1 0 1 0
3 0 2 0
15 0 1 0
105 0 6 0
10 5 2
0 0
2 0
4 0
8 0
100 0
100 0
100 0
100 0
100 0
100 0
-3 0 1 0
1 0 1 0
3 0 2 0
15 0 1 0
105 0 6 0
0 0 0

出力例

0
3
5
11
18
28
20
38

Solution in C (judge verdict: Accepted)

// AOJ 0293 Algorithm Exam
// 2018.3.10 bal4u

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

#define QMAX 3005
typedef struct { int t, s; } QUE;
QUE que[QMAX]; int qsize;

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

void min_heapify(int i)
{
	int l, r, min;
	QUE qt;

	l = LEFT(i), r = RIGHT(i);
	if (l < qsize && que[l].t < que[i].t) min = l; else min = i;
	if (r < qsize && que[r].t < que[min].t) min = r;
	if (min != i) {
		qt = que[i], que[i] = que[min], que[min] = qt;
		min_heapify(min);
	}
}

void deq()
{
	que[0] = que[--qsize];
	min_heapify(0);
}

void enq(int s, int t)
{
	int i, min;
	QUE qt;

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

#define INF 0x10101010
#define MAX 110
typedef struct { int to, rev; int cap, cost; } EDGE;
EDGE edge[MAX][MAX]; int hi[MAX];
int V;				// 頂点数
int potential[MAX], dist[MAX], prevv[MAX], preve[MAX];

void add_edge(int from, int to, int cap, int cost)
{
	int f, t;
	EDGE *ep;

	f = hi[from]++, t = hi[to]++;
	ep = &edge[from][f], ep->to = to, ep->cap = cap, ep->cost = cost, ep->rev = t; 
	ep = &edge[to][t], ep->to = from, ep->cap = 0, ep->cost = -cost, ep->rev = f;
}

int minCostFlow(int S, int T, int F)
{
	int i, v, nv, t, nt, ret;
	EDGE *ep;

	ret = 0;
	memset(potential, 0, V << 2);
  
	while (F > 0) {
		memset(dist, INF, V << 2);
		qsize = 0;
		enq(S, 0), dist[S] = 0;
		while (qsize) {
			v = que[0].s, t = que[0].t, deq();
			if (dist[v] < t) continue;
			for (i = 0; i < hi[v]; i++) {
				ep = &edge[v][i];
				if (ep->cap <= 0) continue;
				nv = ep->to;
				nt = t + ep->cost - potential[nv] + potential[v];
				if(dist[nv] > nt) {
					dist[nv] = nt;
					prevv[nv] = v, preve[nv] = i;
					enq(nv, nt);
				}
			}
		}
		if (dist[T] == INF) return -1;
		for (v = 0; v < V; v++) potential[v] += dist[v];

		t = F;
		for (v = T; v != S; v = prevv[v]) {
			ep = &edge[prevv[v]][preve[v]];
			if (t > ep->cap) t = ep->cap;
		}
		F -= t;

		ret += t * potential[T];
		for (v = T; v != S; v = prevv[v]) {
			ep = &edge[prevv[v]][preve[v]];
			ep->cap -= t;
			edge[v][ep->rev].cap += t;
		}
	}
	return ret;
}

//#define getchar_unlocked()  getchar()
int in()
{
	int n = 0;
	int 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;
}

#define ABS(a)   ((a)>=0?(a):-(a))
int N, M, source, sink;
int ax[101], ay[101];
int bx[6], by[6], c[6], f[6];

int calc(int s, int mi)
{
	int i, j, x;

	memset(hi, 0, V << 2);
	for (i = 0; i < N; i++) add_edge(source, i, 1, 0);
	for (i = 0; i < M; i++) if ((1<<i) & s) {
		for (j = 0; j < N; j++) {
			x = ABS(ax[j]-bx[i]) + ABS(ay[j]-by[i]) - mi;
			if (x < 0) x = 0;
			add_edge(j, N+i, 1, x);
		}
		add_edge(N+i, sink, c[i], 0);
	}
	return minCostFlow(source, sink, N);
}

int main()
{
	int B, i, s, lim, res, cnt, ans;
	int lb, mi, ub, t1, t2;

	while (N = in()) {
		M = in(), B = in();
		for (i = 0; i < N; i++) ax[i] = in(), ay[i] = in();
		for (i = 0; i < M; i++) bx[i] = in(), by[i] = in(), c[i] = in(), f[i] = in();

		source = N + M, sink = source + 1, V = sink + 1;

		ans = INF, lim = 1 << M;
	    for (s = 0; s < lim; s++) {
			res = 0, cnt = 0;
			for (i = 0; i < M; i++) if ((1<<i) & s) res += f[i], cnt++;
			lb = 0, ub = 4001;
			while (1) {
				if (lb + 1 >= ub) {
					res += calc(s, lb) + lb*B*cnt;
					if (ans > res) ans = res;
					break;
				}
				mi = (lb + ub) >> 1;
				if ((t1 = calc(s, mi  ) + mi*B*cnt)     < 0) break;
				if ((t2 = calc(s, mi-1) + (mi-1)*B*cnt) < 0) break;
				if (t1 < t2) lb = mi; else ub = mi;
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}