Problem:
アルゴリズム検定試験
あなたはイズア地区におけるアルゴリズム検定試験を運営しており、運営費を最小にしたいと考えています。運営費は、会場使用料、バスの使用料、移動補助金の総和です。
今年は
N
人の受験者登録があり、それぞれ
c
i
人まで受け入れ可能な
M
個の会場を確保しました。あなたは各受験者を必ずどこかの会場に割り当てなければなりません。1 人以上割り当てた会場については、人数にかかわらず
f
i
円の会場使用料を支払う必要があります。
イズア地区は図に示すように東西方向と南北方向に 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
ax
1
ay
1
ax
2
ay
2
:
ax
N
ay
N
bx
1
by
1
c
1
f
1
bx
2
by
2
c
2
f
2
:
bx
M
by
M
c
M
f
M
1 行目は３つの整数からなる。
N
(1 ≤
N
≤ 100) は受験者の人数、
M
(1 ≤
M
≤ 5) は会場数である。
B
(0 ≤
B
≤ 1000) はシャトルバスを運行する際に、
D
が 1 km 増えたときに加算される料金である。続く
N
行に各受験者の家の座標が与えられる。
ax
i
,
ay
i
(-1000 ≤
ax
i
,
ay
i
≤ 1000) はそれぞれ受験者
i
の家の
x
座標と
y
座標を示す。続く
M
行に各会場の情報が与えられる。
bx
i
,
by
i
(-1000 ≤
bx
i
,
by
i
≤ 1000) はそれぞれ会場
i
の
x
座標と
y
座標を示す。
c
i
(1 ≤
c
i
≤ 100) は会場
i
の受け入れ可能人数、
f
i
(0 ≤
f
i
≤ 100000) は会場
i
の使用料を示す。ただし、
c
1
から
c
M
までの合計は
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

Submitted solutions:

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
#define rep(i, n) for(int i = 0; i < (n); i++)

template<class T>
using vi = vector<T>;

template<class T>
using vii = vector<vi<T>>;

template<class T>
using viii = vector<vii<T>>;


struct MCF {
private:
    const long long inf = 1e18;
    vector<long long> dist;       //最短距離(費用)
    vector<int> pv, pe;     //直前の頂点、辺    

public:
    struct edge {
        int to, rev; long long cap, cost;
        edge(int t = 0, int r = 0, long long ca = 0, long long co = 0)
            : to(t), rev(r), cap(ca), cost(co) {}
    };

    struct pii {
        long long d; int v; //最短距離(費用)、頂点番号
        pii(long long d_ = 0, int v_ = 0) : d(d_), v(v_) {}

        bool operator<(const pii& other) const {
            if (d != other.d) return d < other.d;
            return v < other.v;
        }

        bool operator>(const pii& other) const {
            if (d != other.d) return d > other.d;
            return v > other.v;
        }
    };

    int n;
    vector<vector<edge>> to;
    vector<long long> pot;        //ポテンシャル

    MCF(int n_ = 1) : n(n_), to(n_), pot(n_), dist(n_), pv(n_), pe(n_) {}

    void addedge(int u, int v, long long cap, long long cost) {
        int su = (int)to[u].size();
        int sv = (int)to[v].size();
        to[u].push_back({ v, sv, cap, cost });
        to[v].push_back({ u, su, 0, -cost });
    }

    //s->tへ流量fの最小費用流、流せないときは-1
    long long mincostflow(int s, int t, long long f) {
        long long res = 0;
        pot.assign(n, 0);
        while (f) {
            priority_queue<pii, vector<pii>, greater<pii>> pq;
            dist.assign(n, inf);
            dist[s] = 0;
            pq.push({ 0, s });
            while (!pq.empty()) {
                pii elem = pq.top();
                pq.pop();
                if (dist[elem.v] < elem.d) continue;
                int sv = (int)to[elem.v].size();
                for (int i = 0; i < sv; i++) {
                    edge& nv = to[elem.v][i];
                    if (nv.cap == 0 || dist[nv.to] + pot[nv.to] <= dist[elem.v] + pot[elem.v] + nv.cost) continue;
                    dist[nv.to] = dist[elem.v] + pot[elem.v] - pot[nv.to] + nv.cost;
                    pv[nv.to] = elem.v;
                    pe[nv.to] = i;
                    pq.push({ dist[nv.to], nv.to });
                }
            }

            if (dist[t] == inf) return -1; //流せる最小費用流が存在しない

            for (int v = 0; v < n; v++) pot[v] += dist[v];

            long long nf = f;
            for (int v = t; v != s; v = pv[v]) nf = min(nf, to[pv[v]][pe[v]].cap);
            f -= nf;
            res += nf * (pot[t] - pot[s]); //pot[s] = 0で不要だがポテンシャルを明確化する
            for (int v = t; v != s; v = pv[v]) {
                edge& nv = to[pv[v]][pe[v]];
                nv.cap -= nf;
                to[v][nv.rev].cap += nf;
            }
        }
        return res;
    }
};



int main()
{
    std::cin.tie(nullptr);
    std::ios_base::sync_with_stdio(false);

    vi<ll> res;
    const ll inf = 1e18;
    int n, m, b;
    while (cin >> n >> m >> b, n) {
        vi<ll> ax(n), ay(n), bx(m), by(m), c(m), f(m);
        rep(i, n) cin >> ax[i] >> ay[i];
        rep(i, m) cin >> bx[i] >> by[i] >> c[i] >> f[i];

        ll ans = inf;
        auto dist = [&](int pa, int pb) {
            return abs(ax[pa] - bx[pb]) + abs(ay[pa] - by[pb]);
        };

        

        rep(bit, 1 << m) {
            ll ta = 0;
            int cnt = 0;
            int participants = 0;
            vi<int> dl;
            dl.push_back(0);
            rep(i, m) if(bit >> i & 1) rep(j, n) dl.push_back(dist(j, i));
            sort(dl.begin(), dl.end());
            dl.erase(unique(dl.begin(), dl.end()), dl.end());


            rep(i, m) if (bit >> i & 1) {
                ta += f[i];
                participants += c[i];
                cnt++;
            }
            if (ans <= ta) continue; //暫定解が既に会場使用料より安い
            if (participants < n) continue; //会場人数が受験者より少ない

            ll pf = inf;
            int sz = (int)dl.size();
            int ok = -1, ng = sz;

            auto df = [&](int d) {
                MCF mcf(m + n + 2);
                int S = m + n, T = m + n + 1;

                rep(i, m) if (bit >> i & 1) {
                    mcf.addedge(S, i, c[i], 0);
                    rep(j, n) {
                        mcf.addedge(i, j + m, 1, max(0LL, dist(j, i) - d));
                    }
                }
                rep(j, n) mcf.addedge(j + m, T, 1, 0);
                return mcf.mincostflow(S, T, n) + d * b * cnt;
            };
            
            while (ok + 2 < ng) {
                int lc = (2 * ok + ng) / 3, rc = (ok + 2 * ng) / 3;
                ll fl = df(dl[lc]), fr = df(dl[rc]);
                if (fl < fr) ng = rc;
                else ok = lc;
            }
            ans = min(ans, ta + df(dl[(ok + ng) / 2]));

        }
        res.push_back(ans);
    }
    for (ll elem : res) cout << elem << endl;
    return 0;
}
accuracy: 1
time_ms: 6760
memory_kb: 3468
final_rank: 15

code_snippet: #define READ_FROM_FILE 0

#if READ_FROM_FILE
#include <fstream>
#endif

#include <iostream>
#include <vector>
#include <limits>
#include <queue>
#include <tuple>
using namespace std;

typedef pair<int, int> Pii;
typedef tuple<int, int, int, int> Ti4;


class MinCostFlow {
private:
	class Edge {
	public:
		int to;
		int cap;
		int cost;
		Edge* b_edge;

	public:
		Edge() : to(-1), cap(-1), cost(-1), b_edge(nullptr) {
			return;
		}

		Edge(int to, int cap, int cost, Edge* b) : to(to), cap(cap), cost(cost), b_edge(b) {
			return;
		}

		~Edge() {
			return;
		}
	};

private:
	int num_vertexes_;
	vector<vector<Edge*>> graph_;

public:
	MinCostFlow(int num_vertexes) : num_vertexes_(num_vertexes) {
		graph_ = vector<vector<Edge*>>(num_vertexes);
	}

	~MinCostFlow() {
		for (vector<Edge*>& edges : graph_) {
			for (int i = 0; i < edges.size(); i++) {
				delete edges[i];
			}
		}
		return;
	}

	void add_edge(int from, int to, int cap, int cost) {
		Edge* f_edge = new Edge(to, cap, cost, nullptr);
		Edge* b_edge = new Edge(from, 0, -cost, nullptr);

		f_edge->b_edge = b_edge;
		b_edge->b_edge = f_edge;

		graph_[from].push_back(f_edge);
		graph_[to].push_back(b_edge);
		return;
	}

	int calc_min_cost_flow(int s, int t, int f) {
		int min_cost = 0;
		vector<int> h(num_vertexes_, 0);
		vector<int> prev_v(num_vertexes_, -1);
		vector<Edge*> prev_e(num_vertexes_, nullptr);

		while (f > 0) {
			vector<int> min_dist(num_vertexes_, numeric_limits<int>::max());
			priority_queue<Pii, vector<Pii>, greater<Pii>> q;

			min_dist[s] = 0;
			q.push({ 0, s });
			while (!q.empty()) {
				Pii e = q.top(); q.pop();
				int c_dist = e.first;
				int v = e.second;

				if (min_dist[v] < c_dist) {
					continue;
				}

				for (Edge* edge : graph_[v]) {
					int u = edge->to;
					int cap = edge->cap;
					int cost = edge->cost;
					if (cap > 0) {
						int n_dist = min_dist[v] + cost + h[v] - h[u];
						if (min_dist[u] > n_dist) {
							min_dist[u] = n_dist;
							prev_v[u] = v;
							prev_e[u] = edge;
							q.push({ min_dist[u], u });
						}
					}
				}
			}

			if (min_dist[t] == numeric_limits<int>::max()) {
				return -1;
			}

			for (int v = 0; v < num_vertexes_; v++) {
				h[v] += min_dist[v];
			}

			int d = f;
			int v = t;
			while (v != s) {
				d = min(d, prev_e[v]->cap);
				v = prev_v[v];
			}

			f -= d;
			min_cost += d * h[t];

			v = t;
			while (v != s) {
				Edge* b_edge = prev_e[v]->b_edge;

				prev_e[v]->cap -= d;
				b_edge->cap += d;
				v = prev_v[v];
			}
		}
		return min_cost;
	}
};


int calc_min_cost(int n, const vector<Pii>& a_info, const vector<Ti4>& b_info, int num_vertexes, int s, int t, int b, int d) {
	int m = int(b_info.size());
	MinCostFlow mcf(num_vertexes);
	int bus_cost = d * b * m;
	int site_cost = 0;

	for (const Ti4 b : b_info) {
		site_cost += get<3>(b);
	}
	
	for (int i = 1; i <= n; i++) {
		mcf.add_edge(s, i, 1, 0);
	}
	for (int i = 0; i < m; i++) {
		int c = get<2>(b_info[i]);

		mcf.add_edge(n + 1 + i, t, c, 0);
	}

	for (int i = 0; i < n; i++) {
		int ax = a_info[i].first;
		int ay = a_info[i].second;
		int a_idx = i + 1;

		for (int j = 0; j < m; j++) {
			int bx = get<0>(b_info[j]);
			int by = get<1>(b_info[j]);
			int b_idx = n + 1 + j;
			int dist = abs(bx - ax) + abs(by - ay);
			
			dist = max(dist - d, 0);
			mcf.add_edge(a_idx, b_idx, 1, dist);
		}
	}

	int min_cost = mcf.calc_min_cost_flow(s, t, n);
	return min_cost == -1 ? -1 : min_cost + bus_cost + site_cost;
}


int search_min_cost(int n, int b, const vector<Pii>& a_info, const vector<Ti4>& b_info) {
	int m = int(b_info.size());
	int num_vertexes = n + m + 2;
	int s = 0;
	int t = n + m + 1;
	int left = 0;
	int right = 4001;
	int min_cost = numeric_limits<int>::max();

	while (right - left > 1) {
		int mid = (left + right) / 2;
		int cost0 = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, mid + 1);
		int cost1 = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, mid);
		if (cost0 > cost1) {
			right = mid;
		}
		else {
			left = mid;
		}
	}

	int l_cost = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, left);
	int r_cost = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, right);

	min_cost = min(l_cost, r_cost);
	return min_cost;
}


vector<vector<int>> calc_combinations(int n, int m) {
	vector<int> init_comb(m, -1);
	vector<vector<int>> result;
	vector<pair<int, vector<int>>> stack;
	
	stack.push_back({ 0, init_comb });
	while (!stack.empty()) {
		auto e = stack.back(); stack.pop_back();
		int c_idx = e.first;
		vector<int> c_comb = e.second;
		int n_min = c_idx == 0 ? 0 : c_comb[c_idx - 1] + 1;
		int n_idx = c_idx + 1;
		
		for (int i = n - 1; i >= n_min; i--) {
			vector<int> n_comb = c_comb;
			
			n_comb[c_idx] = i;
			if (n_idx < m) {
				stack.push_back({ n_idx, n_comb });
			}
			else {
				result.push_back(n_comb);
			}
		}
	}
	return result;
}


int main() {
#if READ_FROM_FILE
	ifstream ifs("test0.txt");
	cin.rdbuf(ifs.rdbuf());
#endif
	while (true) {
		int n = -1;
		int m = -1;
		int b = -1;

		cin >> n >> m >> b;
		if (n == 0 && m == 0 && b == 0) {
			break;
		}

		vector<Pii> a_info;
		for (int i = 0; i < n; i++) {
			int x = 0;
			int y = 0;

			cin >> x >> y;
			a_info.push_back({ x, y });
		}

		vector<Ti4> b_info;
		for (int i = 0; i < m; i++) {
			Ti4 e;

			cin >> get<0>(e) >> get<1>(e) >> get<2>(e) >> get<3>(e);
			b_info.push_back(e);
		}

		int min_cost = numeric_limits<int>::max();
		for (int i = 1; i <= m; i++) {
			vector<vector<int>> combs = calc_combinations(m, i);

			for (vector<int>& comb : combs) {
				vector<Ti4> tmp_b_info;
				for (int j = 0; j < i; j++) {
					tmp_b_info.push_back(b_info[comb[j]]);
				}

				int cost = search_min_cost(n, b, a_info, tmp_b_info);
				if (cost >= 0) {
					min_cost = min(min_cost, cost);
				}
			}
		}
		cout << min_cost << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 4240
memory_kb: 3512
final_rank: 8

code_snippet: #define READ_FROM_FILE 0

#if READ_FROM_FILE
#include <fstream>
#endif

#include <iostream>
#include <vector>
#include <limits>
#include <queue>
#include <tuple>
using namespace std;

typedef pair<int, int> Pii;
typedef tuple<int, int, int, int> Ti4;


class MinCostFlow {
private:
	class Edge {
	public:
		int to;
		int cap;
		int cost;
		Edge* b_edge;

	public:
		Edge() : to(-1), cap(-1), cost(-1), b_edge(nullptr) {
			return;
		}

		Edge(int to, int cap, int cost, Edge* b) : to(to), cap(cap), cost(cost), b_edge(b) {
			return;
		}

		~Edge() {
			return;
		}
	};

private:
	int num_vertexes_;
	vector<vector<Edge*>> graph_;

public:
	MinCostFlow(int num_vertexes) : num_vertexes_(num_vertexes) {
		graph_ = vector<vector<Edge*>>(num_vertexes);
	}

	~MinCostFlow() {
		for (vector<Edge*>& edges : graph_) {
			for (int i = 0; i < edges.size(); i++) {
				delete edges[i];
			}
		}
		return;
	}

	void add_edge(int from, int to, int cap, int cost) {
		Edge* f_edge = new Edge(to, cap, cost, nullptr);
		Edge* b_edge = new Edge(from, 0, -cost, nullptr);

		f_edge->b_edge = b_edge;
		b_edge->b_edge = f_edge;

		graph_[from].push_back(f_edge);
		graph_[to].push_back(b_edge);
		return;
	}

	int calc_min_cost_flow(int s, int t, int f) {
		int min_cost = 0;
		vector<int> h(num_vertexes_, 0);
		vector<int> prev_v(num_vertexes_, -1);
		vector<Edge*> prev_e(num_vertexes_, nullptr);

		while (f > 0) {
			vector<int> min_dist(num_vertexes_, numeric_limits<int>::max());
			priority_queue<Pii, vector<Pii>, greater<Pii>> q;

			min_dist[s] = 0;
			q.push({ 0, s });
			while (!q.empty()) {
				Pii e = q.top(); q.pop();
				int c_dist = e.first;
				int v = e.second;

				if (min_dist[v] < c_dist) {
					continue;
				}

				for (Edge* edge : graph_[v]) {
					int u = edge->to;
					int cap = edge->cap;
					int cost = edge->cost;
					if (cap > 0) {
						int n_dist = min_dist[v] + cost + h[v] - h[u];
						if (min_dist[u] > n_dist) {
							min_dist[u] = n_dist;
							prev_v[u] = v;
							prev_e[u] = edge;
							q.push({ min_dist[u], u });
						}
					}
				}
			}

			if (min_dist[t] == numeric_limits<int>::max()) {
				return -1;
			}

			for (int v = 0; v < num_vertexes_; v++) {
				h[v] += min_dist[v];
			}

			int d = f;
			int v = t;
			while (v != s) {
				d = min(d, prev_e[v]->cap);
				v = prev_v[v];
			}

			f -= d;
			min_cost += d * h[t];

			v = t;
			while (v != s) {
				Edge* b_edge = prev_e[v]->b_edge;

				prev_e[v]->cap -= d;
				b_edge->cap += d;
				v = prev_v[v];
			}
		}
		return min_cost;
	}
};


int calc_min_cost(int n, const vector<Pii>& a_info, const vector<Ti4>& b_info, int num_vertexes, int s, int t, int b, int d) {
	int m = int(b_info.size());
	MinCostFlow mcf(num_vertexes);
	int bus_cost = d * b * m;
	int site_cost = 0;

	for (const Ti4 b : b_info) {
		site_cost += get<3>(b);
	}
	
	for (int i = 1; i <= n; i++) {
		mcf.add_edge(s, i, 1, 0);
	}
	for (int i = 0; i < m; i++) {
		int c = get<2>(b_info[i]);

		mcf.add_edge(n + 1 + i, t, c, 0);
	}

	for (int i = 0; i < n; i++) {
		int ax = a_info[i].first;
		int ay = a_info[i].second;
		int a_idx = i + 1;

		for (int j = 0; j < m; j++) {
			int bx = get<0>(b_info[j]);
			int by = get<1>(b_info[j]);
			int b_idx = n + 1 + j;
			int dist = abs(bx - ax) + abs(by - ay);
			
			dist = max(dist - d, 0);
			mcf.add_edge(a_idx, b_idx, 1, dist);
		}
	}

	int min_cost = mcf.calc_min_cost_flow(s, t, n);
	return min_cost == -1 ? -1 : min_cost + bus_cost + site_cost;
}


int search_min_cost(int n, int b, const vector<Pii>& a_info, const vector<Ti4>& b_info) {
	int m = int(b_info.size());
	int num_vertexes = n + m + 2;
	int s = 0;
	int t = n + m + 1;
	int left = 0;
	int right = 2001;
	int min_cost = numeric_limits<int>::max();

	while (right - left > 1) {
		int mid = (left + right) / 2;
		int cost0 = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, mid + 1);
		int cost1 = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, mid);
		if (cost0 > cost1) {
			right = mid;
		}
		else {
			left = mid;
		}
	}

	int l_cost = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, left);
	int r_cost = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, right);

	min_cost = min(l_cost, r_cost);
	return min_cost;
}


vector<vector<int>> calc_combinations(int n, int m) {
	vector<int> init_comb(m, -1);
	vector<vector<int>> result;
	vector<pair<int, vector<int>>> stack;
	
	stack.push_back({ 0, init_comb });
	while (!stack.empty()) {
		auto e = stack.back(); stack.pop_back();
		int c_idx = e.first;
		vector<int> c_comb = e.second;
		int n_min = c_idx == 0 ? 0 : c_comb[c_idx - 1] + 1;
		int n_idx = c_idx + 1;
		
		for (int i = n - 1; i >= n_min; i--) {
			vector<int> n_comb = c_comb;
			
			n_comb[c_idx] = i;
			if (n_idx < m) {
				stack.push_back({ n_idx, n_comb });
			}
			else {
				result.push_back(n_comb);
			}
		}
	}
	return result;
}


int main() {
#if READ_FROM_FILE
	ifstream ifs("test0.txt");
	cin.rdbuf(ifs.rdbuf());
#endif
	while (true) {
		int n = -1;
		int m = -1;
		int b = -1;

		cin >> n >> m >> b;
		if (n == 0 && m == 0 && b == 0) {
			break;
		}

		vector<Pii> a_info;
		for (int i = 0; i < n; i++) {
			int x = 0;
			int y = 0;

			cin >> x >> y;
			a_info.push_back({ x, y });
		}

		vector<Ti4> b_info;
		for (int i = 0; i < m; i++) {
			Ti4 e;

			cin >> get<0>(e) >> get<1>(e) >> get<2>(e) >> get<3>(e);
			b_info.push_back(e);
		}

		int min_cost = numeric_limits<int>::max();
		for (int i = 1; i <= m; i++) {
			vector<vector<int>> combs = calc_combinations(m, i);

			for (vector<int>& comb : combs) {
				vector<Ti4> tmp_b_info;
				for (int j = 0; j < i; j++) {
					tmp_b_info.push_back(b_info[comb[j]]);
				}

				int cost = search_min_cost(n, b, a_info, tmp_b_info);
				if (cost >= 0) {
					min_cost = min(min_cost, cost);
				}
			}
		}
		cout << min_cost << endl;
	}
	return 0;
}
accuracy: 0.625
time_ms: 4000
memory_kb: 3436
final_rank: 18

code_snippet: #define READ_FROM_FILE 0

#if READ_FROM_FILE
#include <fstream>
#endif

#include <iostream>
#include <vector>
#include <limits>
#include <queue>
#include <tuple>
using namespace std;

typedef pair<int, int> Pii;
typedef tuple<int, int, int, int> Ti4;


class MinCostFlow {
private:
	class Edge {
	public:
		int to;
		int cap;
		int cost;
		Edge* b_edge;

	public:
		Edge() : to(-1), cap(-1), cost(-1), b_edge(nullptr) {
			return;
		}

		Edge(int to, int cap, int cost, Edge* b) : to(to), cap(cap), cost(cost), b_edge(b) {
			return;
		}

		~Edge() {
			return;
		}
	};

private:
	int num_vertexes_;
	vector<vector<Edge*>> graph_;

public:
	MinCostFlow(int num_vertexes) : num_vertexes_(num_vertexes) {
		graph_ = vector<vector<Edge*>>(num_vertexes);
	}

	~MinCostFlow() {
		for (vector<Edge*>& edges : graph_) {
			for (int i = 0; i < edges.size(); i++) {
				delete edges[i];
			}
		}
		return;
	}

	void add_edge(int from, int to, int cap, int cost) {
		Edge* f_edge = new Edge(to, cap, cost, nullptr);
		Edge* b_edge = new Edge(from, 0, -cost, nullptr);

		f_edge->b_edge = b_edge;
		b_edge->b_edge = f_edge;

		graph_[from].push_back(f_edge);
		graph_[to].push_back(b_edge);
		return;
	}

	int calc_min_cost_flow(int s, int t, int f) {
		int min_cost = 0;
		vector<int> h(num_vertexes_, 0);
		vector<int> prev_v(num_vertexes_, -1);
		vector<Edge*> prev_e(num_vertexes_, nullptr);

		while (f > 0) {
			vector<int> min_dist(num_vertexes_, numeric_limits<int>::max());
			priority_queue<Pii, vector<Pii>, greater<Pii>> q;

			min_dist[s] = 0;
			q.push({ 0, s });
			while (!q.empty()) {
				Pii e = q.top(); q.pop();
				int c_dist = e.first;
				int v = e.second;

				if (min_dist[v] < c_dist) {
					continue;
				}

				for (Edge* edge : graph_[v]) {
					int u = edge->to;
					int cap = edge->cap;
					int cost = edge->cost;
					if (cap > 0) {
						int n_dist = min_dist[v] + cost + h[v] - h[u];
						if (min_dist[u] > n_dist) {
							min_dist[u] = n_dist;
							prev_v[u] = v;
							prev_e[u] = edge;
							q.push({ min_dist[u], u });
						}
					}
				}
			}

			if (min_dist[t] == numeric_limits<int>::max()) {
				return -1;
			}

			for (int v = 0; v < num_vertexes_; v++) {
				h[v] += min_dist[v];
			}

			int d = f;
			int v = t;
			while (v != s) {
				d = min(d, prev_e[v]->cap);
				v = prev_v[v];
			}

			f -= d;
			min_cost += d * h[t];

			v = t;
			while (v != s) {
				Edge* b_edge = prev_e[v]->b_edge;

				prev_e[v]->cap -= d;
				b_edge->cap += d;
				v = prev_v[v];
			}
		}
		return min_cost;
	}
};


int calc_min_cost(int n, const vector<Pii>& a_info, const vector<Ti4>& b_info, int num_vertexes, int s, int t, int b, int d) {
	int m = int(b_info.size());
	MinCostFlow mcf(num_vertexes);
	int bus_cost = d * b * m;
	int site_cost = 0;

	for (const Ti4 b : b_info) {
		site_cost += get<3>(b);
	}
	
	for (int i = 1; i <= n; i++) {
		mcf.add_edge(s, i, 1, 0);
	}
	for (int i = 0; i < m; i++) {
		int c = get<2>(b_info[i]);

		mcf.add_edge(n + 1 + i, t, c, 0);
	}

	for (int i = 0; i < n; i++) {
		int ax = a_info[i].first;
		int ay = a_info[i].second;
		int a_idx = i + 1;
		for (int j = 0; j < m; j++) {
			int bx = get<0>(b_info[j]);
			int by = get<1>(b_info[j]);
			int b_idx = n + 1 + j;
			int dist = abs(bx - ax) + abs(by - ay);
			
			dist = max(dist - d, 0);
			mcf.add_edge(a_idx, b_idx, 1, dist);
		}
	}

	int min_cost = mcf.calc_min_cost_flow(s, t, n);
	return min_cost == -1 ? -1 : min_cost + bus_cost + site_cost;
}


int search_min_cost(int n, int b, const vector<Pii>& a_info, const vector<Ti4>& b_info) {
	int m = int(b_info.size());
	int num_vertexes = n + m + 2;
	int s = 0;
	int t = n + m + 1;
	int left = 0;
	int right = 10000;
	int min_cost = numeric_limits<int>::max();

	while (right - left > 1) {
		int mid = (left + right) / 2;
		int cost0 = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, mid + 1);
		int cost1 = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, mid);
		if (cost0 > cost1) {
			right = mid;
		}
		else {
			left = mid;
		}
	}

	int l_cost = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, left);
	int r_cost = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, right);

	min_cost = min(l_cost, r_cost);
	return min_cost;
}


vector<vector<int>> calc_combinations(int n, int m) {
	vector<int> init_comb(m, -1);
	vector<vector<int>> result;
	vector<pair<int, vector<int>>> stack;
	
	stack.push_back({ 0, init_comb });
	while (!stack.empty()) {
		auto e = stack.back(); stack.pop_back();
		int c_idx = e.first;
		vector<int> c_comb = e.second;
		int n_min = c_idx == 0 ? 0 : c_comb[c_idx - 1] + 1;
		int n_idx = c_idx + 1;
		
		for (int i = n - 1; i >= n_min; i--) {
			vector<int> n_comb = c_comb;
			
			n_comb[c_idx] = i;
			if (n_idx < m) {
				stack.push_back({ n_idx, n_comb });
			}
			else {
				result.push_back(n_comb);
			}
		}
	}
	return result;
}


int main() {
#if READ_FROM_FILE
	ifstream ifs("test0.txt");
	cin.rdbuf(ifs.rdbuf());
#endif
	while (true) {
		int n = -1;
		int m = -1;
		int b = -1;

		cin >> n >> m >> b;
		if (n == 0 && m == 0 && b == 0) {
			break;
		}

		vector<Pii> a_info;
		for (int i = 0; i < n; i++) {
			int x = 0;
			int y = 0;

			cin >> x >> y;
			a_info.push_back({ x, y });
		}

		vector<Ti4> b_info;
		for (int i = 0; i < m; i++) {
			Ti4 e;

			cin >> get<0>(e) >> get<1>(e) >> get<2>(e) >> get<3>(e);
			b_info.push_back(e);
		}

		int min_cost = numeric_limits<int>::max();
		for (int i = 1; i <= m; i++) {
			vector<vector<int>> combs = calc_combinations(m, i);

			for (vector<int>& comb : combs) {
				vector<Ti4> tmp_b_info;
				for (int j = 0; j < i; j++) {
					tmp_b_info.push_back(b_info[comb[j]]);
				}

				int cost = search_min_cost(n, b, a_info, tmp_b_info);
				if (cost >= 0) {
					min_cost = min(min_cost, cost);
				}
			}
		}
		cout << min_cost << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 4820
memory_kb: 3516
final_rank: 9

code_snippet: #define READ_FROM_FILE 0

#if READ_FROM_FILE
#include <fstream>
#endif

#include <iostream>
#include <vector>
#include <limits>
#include <queue>
#include <tuple>
using namespace std;

typedef pair<int, int> Pii;
typedef tuple<int, int, int, int> Ti4;


class MinCostFlow {
private:
	class Edge {
	public:
		int to;
		int cap;
		int cost;
		Edge* b_edge;

	public:
		Edge() : to(-1), cap(-1), cost(-1), b_edge(nullptr) {
			return;
		}

		Edge(int to, int cap, int cost, Edge* b) : to(to), cap(cap), cost(cost), b_edge(b) {
			return;
		}

		~Edge() {
			return;
		}
	};

private:
	int num_vertexes_;
	vector<vector<Edge*>> graph_;

public:
	MinCostFlow(int num_vertexes) : num_vertexes_(num_vertexes) {
		graph_ = vector<vector<Edge*>>(num_vertexes);
	}

	~MinCostFlow() {
		for (vector<Edge*>& edges : graph_) {
			for (int i = 0; i < edges.size(); i++) {
				delete edges[i];
			}
		}
		return;
	}

	void add_edge(int from, int to, int cap, int cost) {
		Edge* f_edge = new Edge(to, cap, cost, nullptr);
		Edge* b_edge = new Edge(from, 0, -cost, nullptr);

		f_edge->b_edge = b_edge;
		b_edge->b_edge = f_edge;

		graph_[from].push_back(f_edge);
		graph_[to].push_back(b_edge);
		return;
	}

	int calc_min_cost_flow(int s, int t, int f) {
		int min_cost = 0;
		vector<int> h(num_vertexes_, 0);
		vector<int> prev_v(num_vertexes_, -1);
		vector<Edge*> prev_e(num_vertexes_, nullptr);

		while (f > 0) {
			vector<int> min_dist(num_vertexes_, numeric_limits<int>::max());
			priority_queue<Pii, vector<Pii>, greater<Pii>> q;

			min_dist[s] = 0;
			q.push({ 0, s });
			while (!q.empty()) {
				Pii e = q.top(); q.pop();
				int c_dist = e.first;
				int v = e.second;

				if (min_dist[v] < c_dist) {
					continue;
				}

				for (Edge* edge : graph_[v]) {
					int u = edge->to;
					int cap = edge->cap;
					int cost = edge->cost;
					if (cap > 0) {
						int n_dist = min_dist[v] + cost + h[v] - h[u];
						if (min_dist[u] > n_dist) {
							min_dist[u] = n_dist;
							prev_v[u] = v;
							prev_e[u] = edge;
							q.push({ min_dist[u], u });
						}
					}
				}
			}

			if (min_dist[t] == numeric_limits<int>::max()) {
				return numeric_limits<int>::max();
			}

			for (int v = 0; v < num_vertexes_; v++) {
				h[v] += min_dist[v];
			}

			int d = f;
			int v = t;
			while (v != s) {
				d = min(d, prev_e[v]->cap);
				v = prev_v[v];
			}

			f -= d;
			min_cost += d * h[t];

			v = t;
			while (v != s) {
				Edge* b_edge = prev_e[v]->b_edge;

				prev_e[v]->cap -= d;
				b_edge->cap += d;
				v = prev_v[v];
			}
		}
		return min_cost;
	}
};


int calc_min_cost(int n, const vector<Pii>& a_info, const vector<Ti4>& b_info, int num_vertexes, int s, int t, int b, int d) {
	int m = int(b_info.size());
	MinCostFlow mcf(num_vertexes);
	int bus_cost = d * b * m;
	int site_cost = 0;

	for (const Ti4 b : b_info) {
		site_cost += get<3>(b);
	}
	
	for (int i = 1; i <= n; i++) {
		mcf.add_edge(s, i, 1, 0);
	}
	for (int i = 0; i < m; i++) {
		int c = get<2>(b_info[i]);

		mcf.add_edge(n + 1 + i, t, c, 0);
	}

	for (int i = 0; i < n; i++) {
		int ax = a_info[i].first;
		int ay = a_info[i].second;
		int a_idx = i + 1;
		for (int j = 0; j < m; j++) {
			int bx = get<0>(b_info[j]);
			int by = get<1>(b_info[j]);
			int b_idx = n + 1 + j;
			int dist = abs(bx - ax) + abs(by - ay);
			
			dist = max(dist - d, 0);
			mcf.add_edge(a_idx, b_idx, 1, dist);
		}
	}

	int min_cost = mcf.calc_min_cost_flow(s, t, n) + bus_cost + site_cost;
	return min_cost;
}


int search_min_cost(int n, int b, const vector<Pii>& a_info, const vector<Ti4>& b_info) {
	int m = int(b_info.size());
	int num_vertexes = n + m + 2;
	int s = 0;
	int t = n + m + 1;
	int left = 0;
	int right = 10000;
	int min_cost = numeric_limits<int>::max();

	while (right - left > 1) {
		int mid = (left + right) / 2;
		int cost0 = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, mid + 1);
		int cost1 = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, mid);
		if (cost0 > cost1) {
			right = mid;
		}
		else {
			left = mid;
		}
	}

	int l_cost = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, left);
	int r_cost = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, right);

	min_cost = min(l_cost, r_cost);
	return min_cost;
}


vector<vector<int>> calc_combinations(int n, int m) {
	vector<int> init_comb(m, -1);
	vector<vector<int>> result;
	vector<pair<int, vector<int>>> stack;
	
	stack.push_back({ 0, init_comb });
	while (!stack.empty()) {
		auto e = stack.back(); stack.pop_back();
		int c_idx = e.first;
		vector<int> c_comb = e.second;
		int n_min = c_idx == 0 ? 0 : c_comb[c_idx - 1] + 1;
		int n_idx = c_idx + 1;
		
		for (int i = n - 1; i >= n_min; i--) {
			vector<int> n_comb = c_comb;
			
			n_comb[c_idx] = i;
			if (n_idx < m) {
				stack.push_back({ n_idx, n_comb });
			}
			else {
				result.push_back(n_comb);
			}
		}
	}
	return result;
}


int main() {
#if READ_FROM_FILE
	ifstream ifs("test0.txt");
	cin.rdbuf(ifs.rdbuf());
#endif
	while (true) {
		int n = -1;
		int m = -1;
		int b = -1;

		cin >> n >> m >> b;
		if (n == 0 && m == 0 && b == 0) {
			break;
		}

		vector<Pii> a_info;
		for (int i = 0; i < n; i++) {
			int x = 0;
			int y = 0;

			cin >> x >> y;
			a_info.push_back({ x, y });
		}

		vector<Ti4> b_info;
		for (int i = 0; i < m; i++) {
			Ti4 e;

			cin >> get<0>(e) >> get<1>(e) >> get<2>(e) >> get<3>(e);
			b_info.push_back(e);
		}

		int min_cost = numeric_limits<int>::max();
		for (int i = 1; i <= m; i++) {
			vector<vector<int>> combs = calc_combinations(m, i);

			for (vector<int>& comb : combs) {
				vector<Ti4> tmp_b_info;
				for (int j = 0; j < i; j++) {
					tmp_b_info.push_back(b_info[comb[j]]);
				}

				int cost = search_min_cost(n, b, a_info, tmp_b_info);
				if (cost >= 0) {
					min_cost = min(min_cost, cost);
				}
			}
		}
		cout << min_cost << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 4890
memory_kb: 3516
final_rank: 10

code_snippet: #define READ_FROM_FILE 0

#if READ_FROM_FILE
#include <fstream>
#endif

#include <iostream>
#include <vector>
#include <limits>
#include <queue>
#include <tuple>
using namespace std;

typedef pair<int, int> Pii;
typedef tuple<int, int, int, int> Ti4;


class MinCostFlow {
private:
	class Edge {
	public:
		int to;
		int cap;
		int cost;
		Edge* b_edge;

	public:
		Edge() : to(-1), cap(-1), cost(-1), b_edge(nullptr) {
			return;
		}

		Edge(int to, int cap, int cost, Edge* b) : to(to), cap(cap), cost(cost), b_edge(b) {
			return;
		}

		~Edge() {
			return;
		}
	};

private:
	int num_vertexes_;
	vector<vector<Edge*>> graph_;

public:
	MinCostFlow(int num_vertexes) : num_vertexes_(num_vertexes) {
		graph_ = vector<vector<Edge*>>(num_vertexes);
	}

	~MinCostFlow() {
		for (vector<Edge*>& edges : graph_) {
			for (int i = 0; i < edges.size(); i++) {
				delete edges[i];
			}
		}
		return;
	}

	void add_edge(int from, int to, int cap, int cost) {
		Edge* f_edge = new Edge(to, cap, cost, nullptr);
		Edge* b_edge = new Edge(from, 0, -cost, nullptr);

		f_edge->b_edge = b_edge;
		b_edge->b_edge = f_edge;

		graph_[from].push_back(f_edge);
		graph_[to].push_back(b_edge);
		return;
	}

	int calc_min_cost_flow(int s, int t, int f) {
		int min_cost = 0;
		vector<int> h(num_vertexes_, 0);
		vector<int> prev_v(num_vertexes_, -1);
		vector<Edge*> prev_e(num_vertexes_, nullptr);

		while (f > 0) {
			vector<int> min_dist(num_vertexes_, numeric_limits<int>::max());
			priority_queue<Pii, vector<Pii>, greater<Pii>> q;

			min_dist[s] = 0;
			q.push({ 0, s });
			while (!q.empty()) {
				Pii e = q.top(); q.pop();
				int c_dist = e.first;
				int v = e.second;

				if (min_dist[v] < c_dist) {
					continue;
				}

				for (Edge* edge : graph_[v]) {
					int u = edge->to;
					int cap = edge->cap;
					int cost = edge->cost;
					int n_dist = min_dist[v] + cost + h[v] - h[u];
					if (cap > 0 && min_dist[u] > n_dist) {
						min_dist[u] = n_dist;
						prev_v[u] = v;
						prev_e[u] = edge;
						q.push({ min_dist[u], u });
					}
				}
			}

			if (min_dist[t] == numeric_limits<int>::max()) {
				return numeric_limits<int>::max();
			}

			for (int v = 0; v < num_vertexes_; v++) {
				h[v] += min_dist[v];
			}

			int d = f;
			int v = t;
			while (v != s) {
				d = min(d, prev_e[v]->cap);
				v = prev_v[v];
			}

			f -= d;
			min_cost += d * h[t];

			v = t;
			while (v != s) {
				Edge* b_edge = prev_e[v]->b_edge;

				prev_e[v]->cap -= d;
				b_edge->cap += d;
				v = prev_v[v];
			}
		}
		return min_cost;
	}
};


int calc_min_cost(int n, const vector<Pii>& a_info, const vector<Ti4>& b_info, int num_vertexes, int s, int t, int b, int d) {
	int m = int(b_info.size());
	MinCostFlow mcf(num_vertexes);
	int bus_cost = d * b * m;
	int site_cost = 0;

	for (const Ti4 b : b_info) {
		site_cost += get<3>(b);
	}
	
	for (int i = 1; i <= n; i++) {
		mcf.add_edge(s, i, 1, 0);
	}
	for (int i = 0; i < m; i++) {
		int c = get<2>(b_info[i]);

		mcf.add_edge(n + 1 + i, t, c, 0);
	}

	for (int i = 0; i < n; i++) {
		int ax = a_info[i].first;
		int ay = a_info[i].second;
		int a_idx = i + 1;
		for (int j = 0; j < m; j++) {
			int bx = get<0>(b_info[j]);
			int by = get<1>(b_info[j]);
			int b_idx = n + 1 + j;
			int dist = abs(bx - ax) + abs(by - ay);
			
			dist = max(dist - d, 0);
			mcf.add_edge(a_idx, b_idx, 1, dist);
		}
	}

	int min_cost = mcf.calc_min_cost_flow(s, t, n) + bus_cost + site_cost;
	return min_cost;
}


int search_min_cost(int n, int b, const vector<Pii>& a_info, const vector<Ti4>& b_info) {
	int m = int(b_info.size());
	int num_vertexes = n + m + 2;
	int s = 0;
	int t = n + m + 1;
	int left = 0;
	int right = 10000;
	int min_cost = numeric_limits<int>::max();

	while (right - left > 1) {
		int mid = (left + right) / 2;
		int cost0 = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, mid + 1);
		int cost1 = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, mid);
		if (cost0 > cost1) {
			right = mid;
		}
		else {
			left = mid;
		}
	}

	int l_cost = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, left);
	int r_cost = calc_min_cost(n, a_info, b_info, num_vertexes, s, t, b, right);

	min_cost = min(l_cost, r_cost);
	return min_cost;
}


vector<vector<int>> calc_combinations(int n, int m) {
	vector<int> init_comb(m, -1);
	vector<vector<int>> result;
	vector<pair<int, vector<int>>> stack;
	
	stack.push_back({ 0, init_comb });
	while (!stack.empty()) {
		auto e = stack.back(); stack.pop_back();
		int c_idx = e.first;
		vector<int> c_comb = e.second;
		int n_min = c_idx == 0 ? 0 : c_comb[c_idx - 1] + 1;
		int n_idx = c_idx + 1;
		
		for (int i = n - 1; i >= n_min; i--) {
			vector<int> n_comb = c_comb;
			
			n_comb[c_idx] = i;
			if (n_idx < m) {
				stack.push_back({ n_idx, n_comb });
			}
			else {
				result.push_back(n_comb);
			}
		}
	}
	return result;
}


int main() {
#if READ_FROM_FILE
	ifstream ifs("test0.txt");
	cin.rdbuf(ifs.rdbuf());
#endif
	while (true) {
		int n = -1;
		int m = -1;
		int b = -1;

		cin >> n >> m >> b;
		if (n == 0 && m == 0 && b == 0) {
			break;
		}

		vector<Pii> a_info;
		for (int i = 0; i < n; i++) {
			int x = 0;
			int y = 0;

			cin >> x >> y;
			a_info.push_back({ x, y });
		}

		vector<Ti4> b_info;
		for (int i = 0; i < m; i++) {
			Ti4 e;

			cin >> get<0>(e) >> get<1>(e) >> get<2>(e) >> get<3>(e);
			b_info.push_back(e);
		}

		int min_cost = numeric_limits<int>::max();
		for (int i = 1; i <= m; i++) {
			vector<vector<int>> combs = calc_combinations(m, i);

			for (vector<int>& comb : combs) {
				vector<Ti4> tmp_b_info;
				for (int j = 0; j < i; j++) {
					tmp_b_info.push_back(b_info[comb[j]]);
				}

				int cost = search_min_cost(n, b, a_info, tmp_b_info);
				if (cost >= 0) {
					min_cost = min(min_cost, cost);
				}
			}
		}
		cout << min_cost << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 4960
memory_kb: 3516
final_rank: 11

code_snippet: #define READ_FROM_FILE 0

#if READ_FROM_FILE
#include <fstream>
#endif

#include <iostream>
#include <vector>
#include <limits>
#include <queue>
#include <tuple>
using namespace std;

typedef pair<int, int> Pii;
typedef tuple<int, int, int, int> Ti4;


class MinCostFlow {
private:
	class Edge {
	public:
		int to;
		int cap;
		int cost;
		Edge* b_edge;

	public:
		Edge() : to(-1), cap(-1), cost(-1), b_edge(nullptr) {
			return;
		}

		Edge(int to, int cap, int cost, Edge* b) : to(to), cap(cap), cost(cost), b_edge(b) {
			return;
		}

		~Edge() {
			return;
		}
	};

private:
	int num_vertexes_;
	vector<vector<Edge*>> graph_;

public:
	MinCostFlow(int num_vertexes) : num_vertexes_(num_vertexes) {
		graph_ = vector<vector<Edge*>>(num_vertexes);
	}

	~MinCostFlow() {
		for (vector<Edge*>& edges : graph_) {
			for (int i = 0; i < edges.size(); i++) {
				delete edges[i];
			}
		}
		return;
	}

	void add_edge(int from, int to, int cap, int cost) {
		Edge* f_edge = new Edge(to, cap, cost, nullptr);
		Edge* b_edge = new Edge(from, 0, -cost, nullptr);

		f_edge->b_edge = b_edge;
		b_edge->b_edge = f_edge;

		graph_[from].push_back(f_edge);
		graph_[to].push_back(b_edge);
		return;
	}

	int calc_min_cost_flow(int s, int t, int f) {
		int min_cost = 0;
		vector<int> h(num_vertexes_, 0);
		vector<int> prev_v(num_vertexes_, -1);
		vector<Edge*> prev_e(num_vertexes_, nullptr);

		while (f > 0) {
			vector<int> min_dist(num_vertexes_, numeric_limits<int>::max());
			priority_queue<Pii, vector<Pii>, greater<Pii>> q;

			min_dist[s] = 0;
			q.push({ 0, s });
			while (!q.empty()) {
				Pii e = q.top(); q.pop();
				int c_dist = e.first;
				int v = e.second;

				if (min_dist[v] < c_dist) {
					continue;
				}

				for (Edge* edge : graph_[v]) {
					int u = edge->to;
					int cap = edge->cap;
					int cost = edge->cost;
					int n_dist = min_dist[v] + cost + h[v] - h[u];
					if (cap > 0 && min_dist[u] > n_dist) {
						min_dist[u] = n_dist;
						prev_v[u] = v;
						prev_e[u] = edge;
						q.push({ min_dist[u], u });
					}
				}
			}

			if (min_dist[t] == numeric_limits<int>::max()) {
				return numeric_limits<int>::max();
			}

			for (int v = 0; v < num_vertexes_; v++) {
				h[v] += min_dist[v];
			}

			int d = f;
			int v = t;
			while (v != s) {
				d = min(d, prev_e[v]->cap);
				v = prev_v[v];
			}

			f -= d;
			min_cost += d * h[t];

			v = t;
			while (v != s) {
				Edge* b_edge = prev_e[v]->b_edge;

				prev_e[v]->cap -= d;
				b_edge->cap += d;
				v = prev_v[v];
			}
		}
		return min_cost;
	}
};


int calc_min_cost(int n, int m, const vector<Pii>& a_list, const vector<Ti4>& b_list, int num_vertexes, int s, int t, int b, int d) {
	MinCostFlow mcf(num_vertexes);
	int bus_cost = d * b * m;
	int site_cost = 0;

	for (const Ti4 b : b_list) {
		site_cost += get<3>(b);
	}
	
	for (int i = 1; i <= n; i++) {
		mcf.add_edge(s, i, 1, 0);
	}
	for (int i = 0; i < m; i++) {
		int c = get<2>(b_list[i]);

		mcf.add_edge(n + 1 + i, t, c, 0);
	}

	for (int i = 0; i < n; i++) {
		int ax = a_list[i].first;
		int ay = a_list[i].second;
		int a_idx = i + 1;
		for (int j = 0; j < m; j++) {
			int bx = get<0>(b_list[j]);
			int by = get<1>(b_list[j]);
			int b_idx = n + 1 + j;
			int dist = abs(bx - ax) + abs(by - ay);
			
			dist = max(dist - d, 0);
			mcf.add_edge(a_idx, b_idx, 1, dist);
		}
	}

	int min_cost = mcf.calc_min_cost_flow(s, t, n) + bus_cost + site_cost;
	return min_cost;
}


int search_min_cost(int n, int m, int b, const vector<Pii>& a_list, const vector<Ti4>& b_list) {
	int num_vertexes = n + m + 2;
	int s = 0;
	int t = n + m + 1;
	int left = 0;
	int right = 10000;
	int min_cost = numeric_limits<int>::max();

	//for (int i = 0; i < 1001; i++) {
	//	int cost = calc_min_cost(n, m, a_list, b_list, num_vertexes, s, t, b, i);
	//	min_cost = min(min_cost, cost);
	//}

	while (right - left > 1) {
		int mid = (left + right) / 2;
		int cost0 = calc_min_cost(n, m, a_list, b_list, num_vertexes, s, t, b, mid + 1);
		int cost1 = calc_min_cost(n, m, a_list, b_list, num_vertexes, s, t, b, mid);
		if (cost0 > cost1) {
			right = mid;
		}
		else {
			left = mid;
		}
	}

	int l_cost = calc_min_cost(n, m, a_list, b_list, num_vertexes, s, t, b, left);
	int r_cost = calc_min_cost(n, m, a_list, b_list, num_vertexes, s, t, b, right);

	min_cost = min(l_cost, r_cost);
	return min_cost;
}


vector<vector<int>> calc_combinations(int n, int m) {
	vector<int> init_comb(m, -1);
	vector<vector<int>> result;
	vector<pair<int, vector<int>>> stack;
	
	stack.push_back({ 0, init_comb });
	while (!stack.empty()) {
		auto e = stack.back(); stack.pop_back();
		int c_idx = e.first;
		vector<int> c_comb = e.second;
		int n_min = c_idx == 0 ? 0 : c_comb[c_idx - 1] + 1;
		int n_idx = c_idx + 1;
		
		for (int i = n - 1; i >= n_min; i--) {
		//for (int i = n_min; i < n; i++) {
			vector<int> n_comb = c_comb;
			
			n_comb[c_idx] = i;
			if (n_idx < m) {
				stack.push_back({ n_idx, n_comb });
			}
			else {
				result.push_back(n_comb);
			}
		}
	}
	return result;
}


int main() {
#if READ_FROM_FILE
	ifstream ifs("test0.txt");
	cin.rdbuf(ifs.rdbuf());
#endif
	while (true) {
		int n = -1;
		int m = -1;
		int b = -1;

		cin >> n >> m >> b;
		if (n == 0 && m == 0 && b == 0) {
			break;
		}

		vector<Pii> a_list;
		for (int i = 0; i < n; i++) {
			int x = 0;
			int y = 0;

			cin >> x >> y;
			a_list.push_back({ x, y });
		}

		vector<Ti4> b_list;
		for (int i = 0; i < m; i++) {
			Ti4 e;

			cin >> get<0>(e) >> get<1>(e) >> get<2>(e) >> get<3>(e);
			b_list.push_back(e);
		}

		int min_cost = numeric_limits<int>::max();
		for (int i = 1; i <= m; i++) {
			vector<vector<int>> b_idx_lists = calc_combinations(m, i);

			for (vector<int>& comb : b_idx_lists) {
				//cout << comb[0];
				//for (int j = 1; j < i; j++) {
				//	cout << " " << comb[j];
				//}
				//cout << endl;
				vector<Ti4> tmp_b_list;
				for (int j = 0; j < i; j++) {
					tmp_b_list.push_back(b_list[comb[j]]);
				}
				int cost = search_min_cost(n, tmp_b_list.size(), b, a_list, tmp_b_list);
				if (cost >= 0) {
					min_cost = min(min_cost, cost);
				}
			}
		}
		cout << min_cost << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 5100
memory_kb: 3552
final_rank: 14

code_snippet: #include <iostream>
#include <vector>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;

struct Edge {
	int to, cap, cost, rev;
};

class MincostFlow {
	public:
	int size_ = 1;
	vector<vector<Edge>> G;
	vector<int> Potential;
	vector<int> Dist;
	vector<int> Prev_Verts;
	vector<int> Prev_ID;
	vector<bool> Used;
	
	void init(int sz) {
		size_ = sz;
		G.resize(size_ + 2, vector<Edge>{});
		Potential.resize(size_ + 2, 0);
		Dist.resize(size_ + 2, 0);
		Prev_Verts.resize(size_ + 2, 0);
		Prev_ID.resize(size_ + 2, 0);
		Used.resize(size_ + 2, false);
	}
	
	void add_edge(int u, int v, int f, int c) {
		//cout << u << " " << v << " " << f << " " << c << endl;
		G[u].push_back(Edge{v, f,  c, (int)G[v].size()});
		G[v].push_back(Edge{u, 0, -c, (int)G[u].size()-1});
	}
	
	int mincost_flow(int s, int t, int f) {
		int total_cost = 0;
		for (int i = 0; i < size_; i++) Potential[i] = 0;
		
		while (f >= 1) {
			// Initialize
			for (int i = 0; i < size_; i++) Dist[i] = (1 << 30);
			for (int i = 0; i < size_; i++) Prev_Verts[i] = 0;
			for (int i = 0; i < size_; i++) Prev_ID[i] = 0;
			for (int i = 0; i < size_; i++) Used[i] = false;
			
			// Dijkstra (Init)
			priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> Q;
			Q.push(make_pair(0, s)); Dist[s] = 0;
			
			// Dijkstra
			while (!Q.empty()) {
				int pos = Q.top().second; Q.pop();
				if (Used[pos] == true) continue;
				Used[pos] = true;
				for (int i = 0; i < (int)G[pos].size(); i++) {
					if (G[pos][i].cap == 0) continue;
					int to = G[pos][i].to;
					int cost = G[pos][i].cost + Potential[pos] - Potential[to];
					if (Dist[to] > Dist[pos] + cost) {
						Dist[to] = Dist[pos] + cost;
						Prev_Verts[to] = pos;
						Prev_ID[to] = i;
						Q.push(make_pair(Dist[to], to));
					}
				}
			}
			if (Dist[t] == (1 << 30)) return -1;
			
			// Update Path
			int cx = t, min_cap = f;
			while (cx != s) {
				int nex_cx = Prev_Verts[cx];
				int nex_id = Prev_ID[cx];
				min_cap = min(min_cap, G[nex_cx][nex_id].cap);
				cx = nex_cx;
			}
			total_cost += min_cap * (Dist[t] + Potential[t] - Potential[s]);
			f -= min_cap;
			
			// Update Path 2
			cx = t;
			while (cx != s) {
				int nex_cx = Prev_Verts[cx];
				int nex_id = Prev_ID[cx];
				G[nex_cx][nex_id].cap -= min_cap;
				G[G[nex_cx][nex_id].to][G[nex_cx][nex_id].rev].cap += min_cap;
				cx = nex_cx;
			}
			
			// Update Potential
			for (int i = 0; i < size_; i++) Potential[i] += Dist[i];
		}
		
		// Return
		return total_cost;
	}
};

int N, AX[1009], AY[1009];
int M, BX[1009], BY[1009], C[1009], F[1009];
int B;

int GetMin(int mask, int border) {
	MincostFlow Z; Z.init(N + M + 10);
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			if ((mask / (1 << j)) % 2 == 0) continue;
			int dst = abs(AX[i] - BX[j]) + abs(AY[i] - BY[j]);
			dst = max(0, dst - border);
			Z.add_edge(i, N + j, 1, dst);
		}
	}
	
	// Get Initial Cost
	int InitCost = 0;
	for (int i = 0; i < M; i++) {
		if ((mask / (1 << i)) % 2 == 0) continue;
		InitCost += border * B + F[i];
		Z.add_edge(N + i, N + M + 1, C[i], 0);
	}
	for (int i = 0; i < N; i++) Z.add_edge(N + M, i, 1, 0);
	
	// Return
	int val = Z.mincost_flow(N + M, N + M + 1, N);
	if (val == -1) return (1 << 30);
	return val + InitCost;
}

int solve() {
	int Answer = (1 << 30);
	for (int i = 1; i < (1 << M); i++) {
		int cl = 0, cr = 4009, cm;
		for (int j = 0; j < 15; j++) {
			cm = (cl + cr) / 2;
			int val1 = GetMin(i, cm);
			int val2 = GetMin(i, cm + 1);
			if (val1 > val2) { cl = cm; }
			else { cr = cm; }
			Answer = min({Answer, val1, val2});
		}
	}
	return Answer;
}

int main() {
	while (true) {
		// Input
		cin >> N >> M >> B; if (N + M + B == 0) break;
		for (int i = 0; i < N; i++) cin >> AX[i] >> AY[i];
		for (int i = 0; i < M; i++) cin >> BX[i] >> BY[i] >> C[i] >> F[i];
		
		// Solve
		cout << solve() << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 5340
memory_kb: 3528
final_rank: 12

code_snippet: #include <iostream>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
using namespace std;

struct Edge {
	long long to, cap, cost, rev;
};

class MincostFlow {
	public:
	int size_ = 0;
	vector<vector<Edge>> G;
	vector<long long> Potential;
	vector<long long> Dist;
	vector<long long> Prev_Verts;
	vector<long long> Prev_ID;
	vector<bool> Used;
	
	void Initialize(int sz) {
		size_ = sz + 2;
		G.resize(size_, vector<Edge>{});
		Potential.resize(size_, 0);
		Dist.resize(size_, 0);
		Prev_Verts.resize(size_, 0);
		Prev_ID.resize(size_, 0);
		Used.resize(size_, false);
	}
	
	void add_edge(long long u, long long v, long long f, long long c) {
		//cout << "(u, v) = (" << u << ", " << v << "), cap = " << f << ", cost = " << c << endl;
		G[u].push_back(Edge{ v,   f,  c, (int)G[v].size() });
		G[v].push_back(Edge{ u, 0LL, -c, (int)G[u].size() - 1 });
	}
	
	long long mincost_flow(int s, int t, int f) {
		long long current_ans = 0;
		for (int i = 0; i < size_; i++) Potential[i] = 0;
		
		// Loop Phase
		while (f > 0) {
			priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> Q;
			for (int i = 0; i < size_; i++) Dist[i] = (1LL << 60);
			for (int i = 0; i < size_; i++) Prev_Verts[i] = -1;
			for (int i = 0; i < size_; i++) Prev_ID[i] = -1;
			for (int i = 0; i < size_; i++) Used[i] = false;
			Dist[s] = 0;
			Q.push(make_pair(0, s));
			
			// Dijkstra
			while (!Q.empty()) {
				long long pos = Q.top().second; Q.pop();
				if (Used[pos] == true) continue;
				Used[pos] = true;
				for (int i = 0; i < (int)G[pos].size(); i++) {
					if (G[pos][i].cap == 0) continue;
					long long nex = G[pos][i].to;
					long long dst = G[pos][i].cost + Potential[pos] - Potential[nex];
					if (Dist[nex] > Dist[pos] + dst) {
						Dist[nex] = Dist[pos] + dst;
						Prev_Verts[nex] = pos;
						Prev_ID[nex] = i;
						Q.push(make_pair(Dist[nex], nex));
					}
				}
			}
			if (Dist[t] == (1LL << 60)) return -1LL;
			
			// Refresh Edges [Part 1]
			long long current_pos = t;
			long long current_min = f;
			while (current_pos != s) {
				int nex = Prev_Verts[current_pos];
				int idx = Prev_ID[current_pos];
				current_min = min(current_min, G[nex][idx].cap);
				current_pos = nex;
			}
			current_ans += 1LL * current_min * (Dist[t] + Potential[t] - Potential[s]);
			f -= current_min;
			
			// Refresh Edges [Part 2]
			current_pos = t;
			while (current_pos != s) {
				int nex = Prev_Verts[current_pos];
				int idx = Prev_ID[current_pos];
				G[nex][idx].cap -= current_min;
				G[G[nex][idx].to][G[nex][idx].rev].cap += current_min;
				current_pos = nex;
			}
			
			// Refresh Potential
			for (int i = 0; i < size_; i++) {
				if (Dist[i] != (1LL << 60)) Potential[i] += Dist[i];
			}
		}
		
		// Return
		return current_ans;
	}
};

int N, X[1009], Y[1009];
int M, A[1009], B[1009], C[1009], F[1009];
int Bus;

int solve(int Mask, int Border) {
	MincostFlow Z; Z.Initialize(N + M + 10);
	int Total_Cost = 0;
	
	// Add Edges
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			if ((Mask / (1 << j)) % 2 == 0) continue;
			int cost = max(0, abs(A[j] - X[i]) + abs(B[j] - Y[i]) - Border);
			Z.add_edge(i, N + j, 1, cost);
		}
	}
	for (int i = 0; i < N; i++) Z.add_edge(N + M + 0, i, 1, 0);
	for (int i = 0; i < M; i++) {
		if ((Mask / (1 << i)) % 2 == 0) continue;
		Z.add_edge(N + i, N + M + 1, C[i], 0);
		Total_Cost += F[i] + Border * Bus;
	}
	
	// Return
	int val = Z.mincost_flow(N + M, N + M + 1, N);
	if (val == -1) return 2000000000;
	return Total_Cost + val;
}

int main() {
	while (true) {
		// Input
		cin >> N >> M >> Bus; if (N + M + Bus == 0) break;
		for (int i = 0; i < N; i++) cin >> X[i] >> Y[i];
		for (int i = 0; i < M; i++) cin >> A[i] >> B[i] >> C[i] >> F[i];
		
		// Brute Force
		int Answer = (1 << 30);
		for (int i = 1; i < (1 << M); i++) {
			int cl = 0, cr = 4022, cm;
			for (int j = 0; j < 15; j++) {
				cm = (cl + cr) / 2;
				int val1 = solve(i, cm + 0);
				int val2 = solve(i, cm + 1);
				if (val1 > val2) { cl = cm; }
				else { cr = cm; }
				Answer = min(Answer, val1);
				Answer = min(Answer, val2);
				//cout << i << " " << cm << " " << val1 << " " << val2 << endl;
			}
		}
		
		// Output
		cout << Answer << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 5820
memory_kb: 3508
final_rank: 13

code_snippet: #include <iostream>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
using namespace std;

struct Edge {
	long long to, cap, cost, rev;
};

class MincostFlow {
	public:
	int size_ = 0;
	vector<vector<Edge>> G;
	vector<long long> Potential;
	vector<long long> Dist;
	vector<long long> Prev_Verts;
	vector<long long> Prev_ID;
	vector<bool> Used;
	
	void Initialize(int sz) {
		size_ = sz + 2;
		G.resize(size_, vector<Edge>{});
		Potential.resize(size_, 0);
		Dist.resize(size_, 0);
		Prev_Verts.resize(size_, 0);
		Prev_ID.resize(size_, 0);
		Used.resize(size_, false);
	}
	
	void add_edge(long long u, long long v, long long f, long long c) {
		//cout << "(u, v) = (" << u << ", " << v << "), cap = " << f << ", cost = " << c << endl;
		G[u].push_back(Edge{ v,   f,  c, (int)G[v].size() });
		G[v].push_back(Edge{ u, 0LL, -c, (int)G[u].size() - 1 });
	}
	
	long long mincost_flow(int s, int t, int f) {
		long long current_ans = 0;
		for (int i = 0; i < size_; i++) Potential[i] = 0;
		
		// Loop Phase
		while (f > 0) {
			priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> Q;
			for (int i = 0; i < size_; i++) Dist[i] = (1LL << 60);
			for (int i = 0; i < size_; i++) Prev_Verts[i] = -1;
			for (int i = 0; i < size_; i++) Prev_ID[i] = -1;
			for (int i = 0; i < size_; i++) Used[i] = false;
			Dist[s] = 0;
			Q.push(make_pair(0, s));
			
			// Dijkstra
			while (!Q.empty()) {
				long long pos = Q.top().second; Q.pop();
				if (Used[pos] == true) continue;
				Used[pos] = true;
				for (int i = 0; i < (int)G[pos].size(); i++) {
					if (G[pos][i].cap == 0) continue;
					long long nex = G[pos][i].to;
					long long dst = G[pos][i].cost + Potential[pos] - Potential[nex];
					if (Dist[nex] > Dist[pos] + dst) {
						Dist[nex] = Dist[pos] + dst;
						Prev_Verts[nex] = pos;
						Prev_ID[nex] = i;
						Q.push(make_pair(Dist[nex], nex));
					}
				}
			}
			if (Dist[t] == (1LL << 60)) return -1LL;
			
			// Refresh Edges [Part 1]
			long long current_pos = t;
			long long current_min = f;
			while (current_pos != s) {
				int nex = Prev_Verts[current_pos];
				int idx = Prev_ID[current_pos];
				current_min = min(current_min, G[nex][idx].cap);
				current_pos = nex;
			}
			current_ans += 1LL * current_min * (Dist[t] + Potential[t] - Potential[s]);
			f -= current_min;
			
			// Refresh Edges [Part 2]
			current_pos = t;
			while (current_pos != s) {
				int nex = Prev_Verts[current_pos];
				int idx = Prev_ID[current_pos];
				G[nex][idx].cap -= current_min;
				G[G[nex][idx].to][G[nex][idx].rev].cap += current_min;
				current_pos = nex;
			}
			
			// Refresh Potential
			for (int i = 0; i < size_; i++) {
				if (Dist[i] != (1LL << 60)) Potential[i] += Dist[i];
			}
		}
		
		// Return
		return current_ans;
	}
};

int N, X[1009], Y[1009];
int M, A[1009], B[1009], C[1009], F[1009];
int Bus;

int solve(int Mask, int Border) {
	MincostFlow Z; Z.Initialize(N + M + 10);
	int Total_Cost = 0;
	
	// Add Edges
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			if ((Mask / (1 << j)) % 2 == 0) continue;
			int cost = max(0, abs(A[j] - X[i]) + abs(B[j] - Y[i]) - Border);
			Z.add_edge(i, N + j, 1, cost);
		}
	}
	for (int i = 0; i < N; i++) Z.add_edge(N + M + 0, i, 1, 0);
	for (int i = 0; i < M; i++) {
		if ((Mask / (1 << i)) % 2 == 0) continue;
		Z.add_edge(N + i, N + M + 1, C[i], 0);
		Total_Cost += F[i] + Border * Bus;
	}
	
	// Return
	int val = Z.mincost_flow(N + M, N + M + 1, N);
	if (val == -1) return 2000000000;
	return Total_Cost + val;
}

int main() {
	while (true) {
		// Input
		cin >> N >> M >> Bus; if (N + M + Bus == 0) break;
		for (int i = 0; i < N; i++) cin >> X[i] >> Y[i];
		for (int i = 0; i < M; i++) cin >> A[i] >> B[i] >> C[i] >> F[i];
		
		// Brute Force
		int Answer = (1 << 30);
		for (int i = 1; i < (1 << M); i++) {
			int cl = 0, cr = 2022, cm;
			for (int j = 0; j < 15; j++) {
				cm = (cl + cr) / 2;
				int val1 = solve(i, cm + 0);
				int val2 = solve(i, cm + 1);
				if (val1 > val2) { cl = cm; }
				else { cr = cm; }
				Answer = min(Answer, val1);
				Answer = min(Answer, val2);
				//cout << i << " " << cm << " " << val1 << " " << val2 << endl;
			}
		}
		
		// Output
		cout << Answer << endl;
	}
	return 0;
}
accuracy: 0.625
time_ms: 5560
memory_kb: 3548
final_rank: 19

code_snippet: #include<bits/stdc++.h>
#define rep(i,a,...) for(int i = (a)*(strlen(#__VA_ARGS__)!=0);i<(int)(strlen(#__VA_ARGS__)?__VA_ARGS__:(a));++i)
#define per(i,a,...) for(int i = (strlen(#__VA_ARGS__)?__VA_ARGS__:(a))-1;i>=(int)(strlen(#__VA_ARGS__)?(a):0);--i)
#define foreach(i, n) for(auto &i:(n))
#define all(x) (x).begin(), (x).end()
#define bit(x) (1ll << (x))
#define lambda(RES_TYPE, ...) (function<RES_TYPE(__VA_ARGS__)>)[&](__VA_ARGS__) -> RES_TYPE
#define method(FUNC_NAME, RES_TYPE, ...) function<RES_TYPE(__VA_ARGS__)> FUNC_NAME = lambda(RES_TYPE, __VA_ARGS__)
using namespace std;
using ll = long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
//const ll MOD = (ll)1e9+7;
const ll MOD = 998244353;
const int INF = (ll)1e9+7;
const ll INFLL = (ll)1e18;
template<class t>
using vvector = vector<vector<t>>;
template<class t>
using vvvector = vector<vector<vector<t>>>;
template<class t>
using priority_queuer = priority_queue<t, vector<t>, greater<t>>;
template<class t, class u> bool chmax(t &a, u b){if(a<b){a=b;return true;}return false;}
template<class t, class u> bool chmin(t &a, u b){if(a>b){a=b;return true;}return false;}
#ifdef DEBUG
#define debug(x) cout<<"LINE "<<__LINE__<<": "<<#x<<" = "<<x<<endl;
#else
#define debug(x) (void)0
#endif

namespace templates{
    ll modpow(ll x, ll b,ll mod=MOD){
        ll res = 1;
        while(b){
            if(b&1)res = res * x % mod;
            x = x * x % mod;
            b>>=1;
        }
        return res;
    }

    ll modinv(ll x){
        return modpow(x, MOD-2);
    }

    bool was_output = false;

    void print();
    template <class t> void print(const vector<t> &);
    template <class t, class u> void print(const pair<t, u> &);
    template <class t> void print(const t&);
    template <class Head, class... Tail> void print(const Head&, const Tail&...);

    template <class t> void println(const vector<vector<t>>&);
    template <class t> void println(const vector<t>&);
    template <class t> void println(const t&);
    template <class Head, class... Tail> void println(const Head&, const Tail&...);
    void println();
    void newline();

    void print(){
        return;
    }

    template <class t>
    void print(const vector<t>&x){
        for(const t&i:x)print(i);
    }
    template <class t, class u>
    void print(const pair<t,u>&p){
        print(p.first);
        print(p.second);
    }
    template <class t>
    void print(const t&x){
        if(was_output)cout<<" ";
        cout<<x;
        was_output = true;
    }
    template <class Head, class... Tail>
    void print(const Head&head,const Tail&...tail){
        print(head);
        print(tail...);
    }

    template<class t>
    void println(const vector<vector<t>>&x){
        for(vector<t> i:x)println(i);
    }
    template<class t>
    void println(const vector<t>&x){
        for(const t&i:x)print(i);
        println();
    }
    template <class t>
    void println(const t&x){
        print(x);
        println();
    }
    void println(){
        if(was_output){
            cout << endl;
            was_output = false;
        }
    }
    template <class Head, class... Tail>
    void println(const Head&head,const Tail&...tail){
        print(head);
        println(tail...);
    }

    void newline(){
        was_output = true;
        println();
    }

    template<class t>
    istream& operator>>(istream&is, vector<t>&x){
        for(auto &i:x)is >> i;
        return is;
    }

    template<class t, class u>
    istream& operator>>(istream&is, pair<t, u>&x){
        is >> x.first >> x.second;
        return is;
    }

    template<class t>
    ostream& operator<<(ostream&os, vector<t> &v){
        os << "{";
        for(t &i:v){
            os << i << ", ";
        }
        os << "}";
        return os;
    }

    template<class t = long long>
    t in(){
        t res; cin >> res; return res;
    }

    template<class t>
    vector<t> sorted(vector<t> line,function<bool(t,t)> comp=[](t a,t b){return a<b;}){
        sort(line.begin(),line.end(),comp);
        return line;
    }

    template<class t>
    vector<t> reversed(vector<t> line){
        reverse(line.begin(),line.end());
        return line;
    }
    string reversed(string str){
        reverse(str.begin(),str.end());
        return str;
    }

    long long gcd(long long a,long long b){
        while(b){
            a %= b;
            swap(a,b);
        }
        return a;
    }

    long long lcm(long long a,long long b){
        return a / gcd(a,b) * b;
    }

    class output_initializer{
    public:
        output_initializer(){
            ios::sync_with_stdio(false);
            cin.tie(nullptr);
            cout << setprecision(20);
        }
    };output_initializer OUTPUT_INITIALIZER_INSTANCE = output_initializer();
}

using namespace templates;

template< typename flow_t, typename cost_t >
struct PrimalDual {
  const cost_t INF;

  struct edge {
    int to;
    flow_t cap;
    cost_t cost;
    int rev;
    bool isrev;
  };
  vector< vector< edge > > graph;
  vector< cost_t > potential, min_cost;
  vector< int > prevv, preve;

  PrimalDual(int V) : graph(V), INF(numeric_limits< cost_t >::max()) {}

  void add_edge(int from, int to, flow_t cap, cost_t cost) {
    graph[from].emplace_back((edge) {to, cap, cost, (int) graph[to].size(), false});
    graph[to].emplace_back((edge) {from, 0, -cost, (int) graph[from].size() - 1, true});
  }

  cost_t min_cost_flow(int s, int t, flow_t f) {
    int V = (int) graph.size();
    cost_t ret = 0;
    using Pi = pair< cost_t, int >;
    priority_queue< Pi, vector< Pi >, greater< Pi > > que;
    potential.assign(V, 0);
    preve.assign(V, -1);
    prevv.assign(V, -1);

    while(f > 0) {
      min_cost.assign(V, INF);
      que.emplace(0, s);
      min_cost[s] = 0;
      while(!que.empty()) {
        Pi p = que.top();
        que.pop();
        if(min_cost[p.second] < p.first) continue;
        for(int i = 0; i < graph[p.second].size(); i++) {
          edge &e = graph[p.second][i];
          cost_t nextCost = min_cost[p.second] + e.cost + potential[p.second] - potential[e.to];
          if(e.cap > 0 && min_cost[e.to] > nextCost) {
            min_cost[e.to] = nextCost;
            prevv[e.to] = p.second, preve[e.to] = i;
            que.emplace(min_cost[e.to], e.to);
          }
        }
      }
      if(min_cost[t] == INF) return -1;
      for(int v = 0; v < V; v++) potential[v] += min_cost[v];
      flow_t addflow = f;
      for(int v = t; v != s; v = prevv[v]) {
        addflow = min(addflow, graph[prevv[v]][preve[v]].cap);
      }
      f -= addflow;
      ret += addflow * potential[t];
      for(int v = t; v != s; v = prevv[v]) {
        edge &e = graph[prevv[v]][preve[v]];
        e.cap -= addflow;
        graph[v][e.rev].cap += addflow;
      }
    }
    return ret;
  }

  void output() {
    for(int i = 0; i < graph.size(); i++) {
      for(auto &e : graph[i]) {
        if(e.isrev) continue;
        auto &rev_e = graph[e.to][e.rev];
        cout << i << "->" << e.to << " (flow: " << rev_e.cap << "/" << rev_e.cap + e.cap << ")" << endl;
      }
    }
  }
};

int func(int n,int m,int b){
    vector<pii> juken(n);
    vector<pii> kaijo(m);
    vector<int> maxs(m);
    vector<int> cost(m);
    foreach(i,juken)i=in<pii>();
    rep(i,m){
        kaijo[i] = in<pii>();
        maxs[i] = in();
        cost[i] = in();
    }
    method(dist,int,pii a,pii b){
        return abs(a.first-b.first)+abs(a.second-b.second);
    };
    method(cost_with_d,int,pii a,pii b,int d){
        return max(0,dist(a,b)-d);
    };
    method(calc,int,int use,int d){
        ll add = d * b;
        ll res = 0;
        PrimalDual<int,int> pd(n+m+2);
        int start = n + m;
        int end = start + 1;
        rep(i,n){
            pd.add_edge(start,i,1,0);
        }
        int cap = 0;
        rep(i,m){
            if(use&bit(i)){
                rep(j,n){
                    pd.add_edge(j,i+n,1,cost_with_d(juken[j],kaijo[i],d));
                }
                pd.add_edge(i+n,end,maxs[i],0);
                res += cost[i] + add;
                cap += maxs[i];
            }
        }
        if(cap < n)return INF;
        return res + pd.min_cost_flow(start,end,n);
    };
    int res = INF;
    rep(use,bit(m)){
        int cap = 0;
        rep(i,m){
            if(bit(i)&use){
                cap += maxs[i];
            }
        }
        if(cap < n)continue;
        int lp = 0;
        int rp = 2100;
        while(lp < rp-3){
            int mid1 = (lp + lp + rp) / 3;
            int mid2 = (lp + rp + rp) / 3;
            int f1 = calc(use,mid1);
            int f2 = calc(use,mid1);
            if(f1 <= f2){
                rp = mid2;
            }else{
                lp = mid1;
            }
        }
        rep(i,max(0,lp-10),lp+10){
            chmin(res,calc(use,i));
        }
        //rep(i,2000){
        //    chmin(res,calc(use,i));
        //}
    }
    return res;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    while(true){
        int n = in();
        int m = in();
        int b = in();
        if(n==0 and m==0 and b==0)break;
        println(func(n,m,b));
    }
    return 0;
}
accuracy: 0.125
time_ms: 20
memory_kb: 3384
final_rank: 20

code_snippet: #line 1 "a.cpp"
#include<iostream>
#include<algorithm>
using namespace std;
#line 1 "/home/kotatsugame/library/graph/MCF.cpp"
//Minimum Cost Flow O(FE log V)
#line 3 "/home/kotatsugame/library/graph/MCF.cpp"
#include<utility>
#include<vector>
#include<queue>
#include<limits>
template<typename T>
struct MCF{
	struct edge{
		int to,rev,cap;
		T cost;
	};
	vector<vector<edge> >G;
	vector<T>h,d;
	vector<int>pv,pe;
	MCF(int n_=0):G(n_),h(n_,0),d(n_),pv(n_),pe(n_){}
	void add_edge(int from,int to,int cap,T cost)
	{
		G[from].push_back({to,(int)G[to].size(),cap,cost});
		G[to].push_back({from,(int)G[from].size()-1,0,-cost});
	}
	T min_cost_flow(int s,int t,int f)//ans or -1
	{
		T ret=0;
		while(f>0)
		{
			priority_queue<pair<T,int>,vector<pair<T,int> >,greater<pair<T,int> > >P;
			fill(d.begin(),d.end(),numeric_limits<T>::max());
			d[s]=0;
			P.push(make_pair(0,s));
			while(!P.empty())
			{
				pair<T,int>p=P.top();P.pop();
				if(d[p.second]<p.first)continue;
				for(int i=0;i<G[p.second].size();i++)
				{
					edge&e=G[p.second][i];
					if(e.cap>0&&d[e.to]>d[p.second]+e.cost+h[p.second]-h[e.to])
					{
						d[e.to]=d[p.second]+e.cost+h[p.second]-h[e.to];
						pv[e.to]=p.second;
						pe[e.to]=i;
						P.push(make_pair(d[e.to],e.to));
					}
				}
			}
			if(d[t]==numeric_limits<T>::max())return -1;
			for(int u=0;u<G.size();u++)h[u]+=d[u];
			int d=f;
			for(int u=t;u!=s;u=pv[u])d=min(d,G[pv[u]][pe[u]].cap);
			f-=d;
			ret+=d*h[t];
			for(int u=t;u!=s;u=pv[u])
			{
				G[pv[u]][pe[u]].cap-=d;
				G[u][G[pv[u]][pe[u]].rev].cap+=d;
			}
		}
		return ret;
	}
};
#line 5 "a.cpp"
int N,M,B;
int x[100],y[100];
int X[5],Y[5],c[5],F[5];
int f(int mk,int D)
{
	MCF<int>P(N+M+2);
	int st=N+M,go=N+M+1;
	for(int i=0;i<N;i++)
	{
		P.add_edge(st,i,1,0);
		for(int j=0;j<M;j++)if(mk>>j&1)
		{
			P.add_edge(i,N+j,1,max(0,abs(x[i]-X[j])+abs(y[i]-Y[j])-D));
		}
	}
	for(int j=0;j<M;j++)if(mk>>j&1)P.add_edge(N+j,go,c[j],0);
	int ret=P.min_cost_flow(st,go,N);
	if(ret==-1)return 1e9;
	ret+=D*B*__builtin_popcount(mk);
	return ret;
}
main()
{
	while(cin>>N>>M>>B,N)
	{
		for(int i=0;i<N;i++)cin>>x[i]>>y[i];
		for(int i=0;i<M;i++)cin>>X[i]>>Y[i]>>c[i]>>F[i];
		int ans=2e9;
		for(int i=1;i<1<<M;i++)
		{
			int D=0;
			if(f(i,0)<=f(i,1))D=0;
			else
			{
				int L=0,R=5000;
				while(R-L>1)
				{
					int mid=(L+R)/2;
					if(f(i,mid)>f(i,mid+1))L=mid;
					else R=mid;
				}
				D=L+1;
			}
			int now=f(i,D);
			for(int j=0;j<M;j++)if(i>>j&1)now+=F[j];
			ans=min(ans,now);
		}
		cout<<ans<<endl;
	}
}
accuracy: 1
time_ms: 5460
memory_kb: 3168
final_rank: 3

code_snippet: #include <bits/stdc++.h>
#define rep(i,n)for(int i=0;i<(n);i++)
using namespace std;
typedef long long ll;
typedef pair<int,int>P;

const int MOD=1000000007;
const int INF=0x3f3f3f3f;
const ll INFL=0x3f3f3f3f3f3f3f3f;

template<typename flow_t,typename cost_t>
struct PrimalDual{
	const cost_t INF;
	struct edge{
		int to;
		flow_t cap;
		cost_t cost;
		int rev;
		bool isrev;
	};
	vector<vector<edge>>graph;
	vector<cost_t>potential,min_cost;
	vector<int>prevv,preve;

	PrimalDual(int V):INF(numeric_limits<cost_t>::max()),graph(V){}

	void add_edge(int from,int to,flow_t cap,cost_t cost){
		graph[from].emplace_back((edge){to,cap,cost,(int)graph[to].size(),false});
		graph[to].emplace_back((edge){from,0,-cost,(int)graph[from].size()-1,true});
	}
	
	cost_t min_cost_flow(int s,int t,flow_t f){
		int V=(int)graph.size();
		cost_t ret=0;
		using Pi=pair<cost_t,int>;
		priority_queue<Pi,vector<Pi>,greater<Pi>>que;
		potential.assign(V,0);
		preve.assign(V,-1);
		prevv.assign(V,-1);

		while(f>0){
			min_cost.assign(V,INF);
			que.emplace(0,s);
			min_cost[s]=0;
			while(!que.empty()){
				Pi p=que.top();
				que.pop();
				if(min_cost[p.second]<p.first)continue;
				for(int i=0;i<graph[p.second].size();i++){
					edge&e=graph[p.second][i];
					cost_t nextCost=min_cost[p.second]+e.cost+potential[p.second]-potential[e.to];
					if(e.cap>0&&min_cost[e.to]>nextCost){
						min_cost[e.to]=nextCost;
						prevv[e.to]=p.second,preve[e.to]=i;
						que.emplace(min_cost[e.to],e.to);
					}
				}
			}
			if(min_cost[t]==INF)return -1;
			for(int v=0;v<V;v++)potential[v]+=min_cost[v];
			flow_t addflow=f;
			for(int v=t;v!=s;v=prevv[v]){
				addflow=min(addflow,graph[prevv[v]][preve[v]].cap);
			}
			f-=addflow;
			ret+=addflow*potential[t];
			for(int v=t;v!=s;v=prevv[v]){
				edge&e=graph[prevv[v]][preve[v]];
				e.cap-=addflow;
				graph[v][e.rev].cap+=addflow;
			}
		}
		return ret;
	}
};

int ax[200],ay[200];
int bx[6],by[6],c[6],f[6];

int n,m,b;

int M;
vector<int>v;

ll calc(int t){
	PrimalDual<ll,ll>flow(n+M+2);
	int s=n+M,g=n+M+1;
	rep(i,n){
		flow.add_edge(s,i,1,0);
	}
	rep(i,M){
		flow.add_edge(n+i,g,c[v[i]],0);
	}
	rep(i,n)rep(j,M){
		int d=abs(bx[v[j]]-ax[i])+abs(by[v[j]]-ay[i]);
		d=max(0,d-t);
		flow.add_edge(i,n+j,1,d);
	}
	return flow.min_cost_flow(s,g,n)+t*b*M;
}

int main(){
	while(cin>>n>>m>>b,n){
		rep(i,n){
			scanf("%d%d",&ax[i],&ay[i]);
		}
		rep(i,m){
			scanf("%d%d%d%d",&bx[i],&by[i],&c[i],&f[i]);
		}
		ll Min=INFL;
		rep(S,1<<m){
			ll cost=0;
			int cap=0;
			v.clear();
			rep(j,m){
				if(S>>j&1)cost+=f[j],cap+=c[j],v.push_back(j);
			}
			if(cap<n)continue;
			M=v.size();
			int ok=-1,ng=5000;//cost(i)>=cost(i+1)

			while(ng-ok>1){
				int t=(ok+ng)/2;
				if(calc(t)>=calc(t+1))ok=t;
				else ng=t;
			}
			Min=min(Min,cost+calc(ng));
		}
		cout<<Min<<endl;
	}
}
accuracy: 1
time_ms: 4810
memory_kb: 3316
final_rank: 5

code_snippet: #include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <numeric>
#include <bitset>
#include <cmath>

static const int MOD = 1000000007;
using ll = long long;
using u32 = unsigned;
using u64 = unsigned long long;
using namespace std;

template<class T> constexpr T INF = ::numeric_limits<T>::max()/32*15+208;

template <class K, class V>
class RadixHeap {
    static constexpr int bit_length = sizeof(K)*8;
    K last;
    size_t sz, cnt;
    array<vector<pair<K, V>>, bit_length> v;
    static inline int bsr(int x){
        return x ? bit_length-__builtin_clz(x) : 0;
    }
    static inline int bsr(ll x){
        return x ? bit_length-__builtin_clzll(x) : 0;
    }

    void pull() {
        if(cnt < v[0].size()) return;;
        int i = 1;
        while(v[i].empty()) i++;
        last = min_element(v[i].begin(),v[i].end())->first;
        for (auto &&x : v[i]) v[bsr(x.first ^ last)].push_back(x);
        v[i].clear();
    }
public:
    RadixHeap() : last(0), sz(0), cnt(0) {}
    void emplace(K x, V val){
        sz++;
        v[bsr(x^last)].emplace_back(x, val);
    }

    pair<K, V> top() {
        pull();
        return v[0][cnt];
    }

    void pop() {
        pull();
        sz--;
        cnt++;
    }

    size_t size() const { return sz; }
    bool empty() const { return !sz; }
};

template<typename F, typename C>
struct PrimalDual {
    struct edge {
        int to; F cap; C cost; int rev;
        edge() = default;
        edge(int to, F cap, C cost, int rev):to(to), cap(cap), cost(cost), rev(rev) {};
    };
    vector<vector<edge>> G;
    vector<C> potential, min_cost;
    vector<int> prevv, preve;

    explicit PrimalDual(int n) : G(n), potential(n), min_cost(n), prevv(n), preve(n) {}

    void add_edge(int u, int v, F cap, C cost){
        G[u].emplace_back(v, cap, cost, G[v].size());
        G[v].emplace_back(u, 0, -cost, G[u].size()-1);
    }


    void dijkstra(int s){

        RadixHeap<C, int> Q;
        fill(min_cost.begin(),min_cost.end(), INF<C>);
        min_cost[s] = 0;
        Q.emplace(0, s);
        while(!Q.empty()){
            pair<C, int> p = Q.top(); Q.pop();
            int v = p.second;
            if(min_cost[v] < p.first) continue;
            for(int i = 0; i < G[v].size(); ++i){
                edge &e=G[v][i];
                if(e.cap==0) continue;
                if(min_cost[v]+e.cost+potential[v]-potential[e.to] < min_cost[e.to]){
                    min_cost[e.to] = min_cost[v]+e.cost+potential[v]-potential[e.to];
                    prevv[e.to] = v;
                    preve[e.to] = i;
                    Q.emplace(min_cost[e.to], e.to);
                }
            }
        }
    }

    C flow(int s, int t, F fl, int &ok){
        C res = 0;
        fill(potential.begin(),potential.end(), 0);
        while(fl > 0){
            dijkstra(s);
            if(min_cost[t] == INF<C>){
                ok = 0;
                return res;
            }
            for (int i = 0; i < potential.size(); ++i) {
                if(min_cost[i] < INF<C>) potential[i] += min_cost[i];
            }

            F d = fl;
            for(int v = t; v != s; v = prevv[v]){
                d = min(d, G[prevv[v]][preve[v]].cap);
            }
            fl -= d;
            res += potential[t]*d;
            for(int v = t; v != s; v = prevv[v]){
                G[prevv[v]][preve[v]].cap -= d;
                G[v][G[prevv[v]][preve[v]].rev].cap += d;
            }
        }
        ok = 1;
        return res;
    }
};

void solve(int n, int m, int b){
    vector<int> ax(n), ay(n);
    for (int i = 0; i < n; ++i) {
        cin >> ax[i] >> ay[i];
    }
    vector<int> bx(m), by(m), c(m), v(m);
    for (int i = 0; i < m; ++i) {
        cin >> bx[i] >> by[i] >> c[i] >> v[i];
    }
    int ans = INF<int>;
    for (int i = 1; i < (1 << m); ++i) {
        auto f = [&](int x) -> int {
            PrimalDual<int, int> G(2+m+n);
            int ans = 0;
            for (int j = 0; j < m; ++j) {
                if(i & (1 << j)){
                    ans += v[j]+b*x;
                    G.add_edge(0, j+2, c[j], 0);
                    for (int k = 0; k < n; ++k) {
                        G.add_edge(j+2, m+2+k, 1, max(0, (abs(ax[k]-bx[j])+abs(ay[k]-by[j]))-x));
                    }
                }
            }
            for (int j = 0; j < n; ++j) {
                G.add_edge(m+2+j, 1, 1, 0);
            }
            int flg = 0;
            ans += G.flow(0, 1, n, flg);
            if(!flg) return INF<int>;
            else return ans;
        };
        int ok = 0, ng = 5000;
        while(ng-ok > 1){
            int mid = (ng+ok)/2;
            if(f(mid-1) >= f(mid)) ok = mid;
            else ng = mid;
        }
        ans = min(ans, f(ok));
    }
    cout << ans << "\n";
}

int main() {
    int n, m, b;
    while(cin >> n >> m >> b, n){
        solve(n, m, b);
    }
    return 0;
}
accuracy: 1
time_ms: 5310
memory_kb: 3196
final_rank: 4

code_snippet: #include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <numeric>
#include <bitset>
#include <cmath>

static const int MOD = 1000000007;
using ll = long long;
using u32 = unsigned;
using u64 = unsigned long long;
using namespace std;

template<class T> constexpr T INF = ::numeric_limits<T>::max()/32*15+208;

template <class K, class V>
class RadixHeap {
    static constexpr int bit_length = sizeof(K)*8;
    K last;
    size_t sz, cnt;
    array<vector<pair<K, V>>, bit_length> v;
    static inline int bsr(int x){
        return x ? bit_length-__builtin_clz(x) : 0;
    }
    static inline int bsr(ll x){
        return x ? bit_length-__builtin_clzll(x) : 0;
    }

    void pull() {
        if(cnt < v[0].size()) return;;
        int i = 1;
        while(v[i].empty()) i++;
        last = min_element(v[i].begin(),v[i].end())->first;
        for (auto &&x : v[i]) v[bsr(x.first ^ last)].push_back(x);
        v[i].clear();
    }
public:
    RadixHeap() : last(0), sz(0), cnt(0) {}
    void emplace(K x, V val){
        sz++;
        v[bsr(x^last)].emplace_back(x, val);
    }

    pair<K, V> top() {
        pull();
        return v[0][cnt];
    }

    void pop() {
        pull();
        sz--;
        cnt++;
    }

    size_t size() const { return sz; }
    bool empty() const { return !sz; }
};

template<typename F, typename C>
struct PrimalDual {
    struct edge {
        int to; F cap; C cost; int rev;
        edge() = default;
        edge(int to, F cap, C cost, int rev):to(to), cap(cap), cost(cost), rev(rev) {};
    };
    vector<vector<edge>> G;
    vector<C> potential, min_cost;
    vector<int> prevv, preve;

    explicit PrimalDual(int n) : G(n), potential(n), min_cost(n), prevv(n), preve(n) {}

    void add_edge(int u, int v, F cap, C cost){
        G[u].emplace_back(v, cap, cost, G[v].size());
        G[v].emplace_back(u, 0, -cost, G[u].size()-1);
    }


    void dijkstra(int s){

        RadixHeap<C, int> Q;
        fill(min_cost.begin(),min_cost.end(), INF<C>);
        min_cost[s] = 0;
        Q.emplace(0, s);
        while(!Q.empty()){
            pair<C, int> p = Q.top(); Q.pop();
            int v = p.second;
            if(min_cost[v] < p.first) continue;
            for(int i = 0; i < G[v].size(); ++i){
                edge &e=G[v][i];
                if(e.cap==0) continue;
                if(min_cost[v]+e.cost+potential[v]-potential[e.to] < min_cost[e.to]){
                    min_cost[e.to] = min_cost[v]+e.cost+potential[v]-potential[e.to];
                    prevv[e.to] = v;
                    preve[e.to] = i;
                    Q.emplace(min_cost[e.to], e.to);
                }
            }
        }
    }

    C flow(int s, int t, F fl, int &ok){
        C res = 0;
        fill(potential.begin(),potential.end(), 0);
        while(fl > 0){
            dijkstra(s);
            if(min_cost[t] == INF<C>){
                ok = 0;
                return res;
            }
            for (int i = 0; i < potential.size(); ++i) {
                if(min_cost[i] < INF<C>) potential[i] += min_cost[i];
            }

            F d = fl;
            for(int v = t; v != s; v = prevv[v]){
                d = min(d, G[prevv[v]][preve[v]].cap);
            }
            fl -= d;
            res += potential[t]*d;
            for(int v = t; v != s; v = prevv[v]){
                G[prevv[v]][preve[v]].cap -= d;
                G[v][G[prevv[v]][preve[v]].rev].cap += d;
            }
        }
        ok = 1;
        return res;
    }
};

void solve(int n, int m, int b){
    vector<int> ax(n), ay(n);
    for (int i = 0; i < n; ++i) {
        cin >> ax[i] >> ay[i];
    }
    vector<int> bx(m), by(m), c(m), v(m);
    for (int i = 0; i < m; ++i) {
        cin >> bx[i] >> by[i] >> c[i] >> v[i];
    }
    int ans = INF<int>;
    for (int i = 1; i < (1 << m); ++i) {
        auto f = [&](int x) -> int {
            PrimalDual<int, int> G(2+m+n);
            int ans = 0;
            for (int j = 0; j < m; ++j) {
                if(i & (1 << j)){
                    ans += v[j]+b*x;
                    G.add_edge(0, j+2, c[j], 0);
                    for (int k = 0; k < n; ++k) {
                        G.add_edge(j+2, m+2+k, 1, max(0, (abs(ax[k]-bx[j])+abs(ay[k]-by[j]))-x));
                    }
                }
            }
            for (int j = 0; j < n; ++j) {
                G.add_edge(m+2+j, 1, 1, 0);
            }
            int flg = 0;
            ans += G.flow(0, 1, n, flg);
            if(!flg) return INF<int>;
            else return ans;
        };
        int ok = 0, ng = 2100;
        while(ng-ok > 1){
            int mid = (ng+ok)/2;
            if(f(mid-1) >= f(mid)) ok = mid;
            else ng = mid;
        }
        ans = min(ans, f(ok));
    }
    cout << ans << "\n";
}

int main() {
    int n, m, b;
    while(cin >> n >> m >> b, n){
        solve(n, m, b);
    }
    return 0;
}
accuracy: 0.625
time_ms: 4470
memory_kb: 3212
final_rank: 16

code_snippet: #include<iostream>
#include<vector>
#include<complex>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#define rep(i,n) for(int i = 0;i < n ; ++i)

using namespace std;

using ll = long long;

struct edge{int to, cap, cost, rev;};

struct mincostflow{
    vector<vector<edge>> G;
    vector<int> par, dist;
    mincostflow(int n):G(n),par(n),dist(n){}
    void add_edge(int from, int to, int cap, int cost){
        G[from].push_back({to,cap,cost,(int)G[to].size()});
        G[to].push_back({from,0,-cost,(int)G[from].size()-1});
    }

    int minimum_load(int s,int t){
        fill(par.begin(),par.end(),-1);
        fill(dist.begin(),dist.end(),1e9+7);
        dist[s]=0;
        priority_queue<pair<int,int>,vector<pair<int,int>>, greater<pair<int,int>>> pq;
        pq.push({0,s});
        while(pq.size()){
            auto p = pq.top();pq.pop();
            int id = p.second;
            if(id==t)continue;
            if(p.first>dist[id])continue;
            for(auto e : G[id]){
                if(e.cap>0){
                    int nd = p.first + e.cost;
                    if(nd<dist[e.to]){
                        dist[e.to]=nd;
                        par[e.to]=id;
                        pq.push({nd,e.to});
                    }
                }
            }
        }
        int cur = t;
        while(cur!=s){
            int p = par[cur];
            if(p<0)return -1;
            for(auto& e : G[p]){
                if(e.cap>0&&e.to==cur&&dist[p]+e.cost==dist[cur]){
                    e.cap--;
                    G[cur][e.rev].cap++;
                    break;
                }
            }cur=p;
        }
        return dist[t];
    }
    int minimum_cost_flow(int s,int t,int k){
        int ret = 0;
        rep(i,k){
            int z = minimum_load(s, t);
            if(z<0)return -1;
            ret += z;
        }
        return ret;
    }
};
int ax[111],ay[111];
int bx[10],by[10],c[10],f[10];
int n,m,b;


int calc(int d,int mask){
    mincostflow mcf(n+m+2);
    int s = n+m,t = n+m+1;
    rep(j,m){
        if(((1<<j)&mask)==0)continue;
        mcf.add_edge(n+j, t, c[j], 0);
        rep(i,n){
            int dist = max(0,abs(ax[i]-bx[j])+abs(ay[i]-by[j])-d);
            mcf.add_edge(i, n+j, 1, dist);
        }
    }
    rep(i,n)mcf.add_edge(s, i, 1, 0);
    int ret = mcf.minimum_cost_flow(s,t,n);
    if(ret==-1)ret=1e9+7;
    return ret+d*b*__builtin_popcount(mask);
}
void solve(){
    rep(i,n)cin>>ax[i]>>ay[i];
    rep(i,m){
        cin>>bx[i]>>by[i]>>c[i]>>f[i];
    }
    int ans = 1ll<<30;
    int all = 1<<m;
    rep(i,all){
        int cost = 0;
        int cap = 0;
        rep(j,m){
            if(i&(1<<j)){
                cost+=f[j];
                cap += c[j];
            }
        }
        if(cap<n)continue;
        int l = 0, r = 4001;
        while(r-l>2){
            int ml = (2*l+r)/3, mr = (l+2*r)/3;
            int vl = calc(ml,i);
            int vr = calc(mr,i);
            if(vl>vr)l=ml;
            else r=mr;
        }
        ans = min(calc(l,i)+cost,ans);
        ans = min(calc(l+1,i)+cost,ans);
        ans = min(calc(l+2,i)+cost,ans);
    }
    cout<<ans<<endl;
}

int main(){
    while(cin>>n>>m>>b,n!=0)solve();

}
accuracy: 1
time_ms: 7950
memory_kb: 3192
final_rank: 7

code_snippet: #include<iostream>
#include<vector>
#include<complex>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#define rep(i,n) for(int i = 0;i < n ; ++i)

using namespace std;

using ll = long long;

struct edge{int to, cap, cost, rev;};

struct mincostflow{
    vector<vector<edge>> G;
    vector<int> par, dist;
    mincostflow(int n):G(n),par(n),dist(n){}
    void add_edge(int from, int to, int cap, int cost){
        G[from].push_back({to,cap,cost,(int)G[to].size()});
        G[to].push_back({from,0,-cost,(int)G[from].size()-1});
    }

    int minimum_load(int s,int t){
        fill(par.begin(),par.end(),-1);
        fill(dist.begin(),dist.end(),1e9+7);
        dist[s]=0;
        priority_queue<pair<int,int>,vector<pair<int,int>>, greater<pair<int,int>>> pq;
        pq.push({0,s});
        while(pq.size()){
            auto p = pq.top();pq.pop();
            int id = p.second;
            if(id==t)continue;
            if(p.first>dist[id])continue;
            for(auto e : G[id]){
                if(e.cap>0){
                    int nd = p.first + e.cost;
                    if(nd<dist[e.to]){
                        dist[e.to]=nd;
                        par[e.to]=id;
                        pq.push({nd,e.to});
                    }
                }
            }
        }
        int cur = t;
        while(cur!=s){
            int p = par[cur];
            if(p<0)return -1;
            for(auto& e : G[p]){
                if(e.cap>0&&e.to==cur&&dist[p]+e.cost==dist[cur]){
                    e.cap--;
                    G[cur][e.rev].cap++;
                    break;
                }
            }cur=p;
        }
        return dist[t];
    }
    int minimum_cost_flow(int s,int t,int k){
        int ret = 0;
        rep(i,k){
            int z = minimum_load(s, t);
            if(z<0)return -1;
            ret += z;
        }
        return ret;
    }
};
int ax[111],ay[111];
int bx[10],by[10],c[10],f[10];
int n,m,b;


int calc(int d,int mask){
    mincostflow mcf(n+m+2);
    int s = n+m,t = n+m+1;
    rep(j,m){
        if(((1<<j)&mask)==0)continue;
        mcf.add_edge(n+j, t, c[j], 0);
        rep(i,n){
            int dist = max(0,abs(ax[i]-bx[j])+abs(ay[i]-by[j])-d);
            mcf.add_edge(i, n+j, 1, dist);
        }
    }
    rep(i,n)mcf.add_edge(s, i, 1, 0);
    int ret = mcf.minimum_cost_flow(s,t,n);
    if(ret==-1)ret=1e9+7;
    return ret+d*b*__builtin_popcount(mask);
}
void solve(){
    rep(i,n)cin>>ax[i]>>ay[i];
    rep(i,m){
        cin>>bx[i]>>by[i]>>c[i]>>f[i];
    }
    int ans = 1ll<<30;
    int all = 1<<m;
    rep(i,all){
        int cost = 0;
        rep(j,m)if(i&(1<<j))cost+=f[j];
        int l = 0, r = 2000;
        while(r-l>2){
            int ml = (2*l+r)/3, mr = (l+2*r)/3;
            int vl = calc(ml,i);
            int vr = calc(mr,i);
            if(vl>vr)l=ml;
            else r=mr;
        }
        ans = min(calc(l,i)+cost,ans);
        ans = min(calc(l+1,i)+cost,ans);
        ans = min(calc(l+2,i)+cost,ans);
    }
    cout<<ans<<endl;
}

int main(){
    while(cin>>n>>m>>b,n!=0)solve();

}
accuracy: 0.625
time_ms: 7070
memory_kb: 3200
final_rank: 17

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <functional>
#include <map>
#include <climits>
#include <stack>
#include <string>
#include <random>
#include<set>
#include <iomanip>
#include <climits>
#include <memory>
#include <cassert>
struct Point {
	int x, y;
	int manhattan_distance(const Point &other) const { return std::abs(x - other.x) + std::abs(y - other.y); }
};
struct Key_with_value {
	int key, value;
	bool operator>(const Key_with_value &kv) const { return key > kv.key; }
};
struct Edge {
	int to, cost, pair;
	bool can_use;
};
std::vector<std::vector<Edge>> make_graph(const std::vector<Point> &person, const std::vector<Point> &hall) {
	std::vector<std::vector<Edge>> result(person.size() + hall.size() + 2);
	const int start = 0;
	const int goal = result.size() - 1;
	result[start] = std::vector<Edge>(person.size());
	result[goal] = std::vector<Edge>(hall.size());
	for (auto i = 0; i < person.size(); ++i) {
		result[i + 1] = std::vector<Edge>(hall.size() + 1);
		result[i + 1][0] = Edge{ start, 0, i, false };
		result[start][i] = Edge{ i + 1, 0, 0, true};
	}
	for (auto i = 0; i < hall.size(); ++i) {
		result[i + person.size() + 1] = std::vector<Edge>(person.size() + 1);
		result[i + person.size() + 1][0] = Edge{ goal, 0, i, true };
		result[goal][i] = Edge{ i + (int)person.size() + 1, 0, 0, false };
	}
	for (auto p = 0; p < person.size(); ++p) {
		for (auto h = 0; h < hall.size(); ++h) {
			auto distance = person[p].manhattan_distance(hall[h]);
			result[p + 1][h + 1] = Edge{ h + (int)person.size() + 1, distance, p + 1, true };
			result[h + person.size() + 1][p + 1] = { p + 1, -distance, h + 1, false};
		}
	}
	return result;
}
int min_cost_max_flow(std::vector<std::vector<Edge>> nodes, std::vector<int> capacities, const int distance) {
	std::vector<int> potential(nodes.size(), 0);
	std::vector<int> min_cost(nodes.size(), 0);
	std::vector<Edge*> prev_edge(nodes.size(), nullptr);
	const int start = 0;
	const int goal = nodes.size() - 1;
	const int separation = nodes.size() - 1 - capacities.size();
	int result = 0;
	for (auto &line : nodes) for (auto &cell : line) {
		if (cell.cost > distance) cell.cost -= distance;
		else if (cell.cost < -distance) cell.cost += distance;
		else cell.cost = 0;
	}
	std::priority_queue<Key_with_value, std::vector<Key_with_value>, std::greater<Key_with_value>> queue;
	while (true) {
		for (auto i = 1; i < min_cost.size(); ++i) min_cost[i] = INT_MAX;
		queue.push(Key_with_value{ 0, start });
		while (!queue.empty()) {
			auto top = queue.top(); queue.pop();
			if (min_cost[top.value] == top.key) {
				for (const auto &next : nodes[top.value]) {
					if (!next.can_use) continue;
					if (min_cost[next.to] > top.key + next.cost + potential[top.value] - potential[next.to]) {
						min_cost[next.to] = top.key + next.cost + potential[top.value] - potential[next.to];
						prev_edge[next.to] = &nodes[next.to][next.pair];
						if (next.to != goal) queue.push({ min_cost[next.to], next.to });
					}
				}
			}
		}
		if (min_cost[goal] != INT_MAX) {
			result += min_cost[goal];
			--capacities[prev_edge[goal]->to - separation];
			if (capacities[prev_edge[goal]->to - separation] == 0) {
				nodes[prev_edge[goal]->to][prev_edge[goal]->pair].can_use = false;
			}
			auto last = prev_edge[goal]->to;
			while (last != start) {
				prev_edge[last]->can_use = true;
				nodes[prev_edge[last]->to][prev_edge[last]->pair].can_use = false;
				last = prev_edge[last]->to;
			}
			for (auto i = 1; i < potential.size() - 1; ++i) potential[i] += min_cost[i];
		}
		else {
			break;
		}
	}
	return result;
}
void solve() {
	int n, m, b; std::cin >> n >> m >> b;
	if (n == 0) return;
	std::vector<Point> persons(n); for (auto &person : persons) std::cin >> person.x >> person.y;
	std::vector<Point> halls(m); std::vector<int> capacities(m); std::vector<int> fees(m);
	for (auto i = 0; i < m; ++i) std::cin >> halls[i].x >> halls[i].y >> capacities[i] >> fees[i];
	int min = INT_MAX;
	for (auto usage = 1; usage < (1 << m); ++usage) {
		std::vector<Point> use_hall;
		std::vector<int> use_capacities;
		int sum_capacity = 0;
		int sum_fee = 0;
		for (auto i = 0; i < m; ++i) {
			if (((1 << i) & usage) != 0) {
				use_hall.push_back(halls[i]);
				use_capacities.push_back(capacities[i]);
				sum_capacity += capacities[i];
				sum_fee += fees[i];
			}
		}
		if (sum_capacity >= n) {
			auto nodes = make_graph(persons, use_hall);
			auto left = 0;
			auto right = 4000;
			while (left < right) {
				auto mid = (left + right) / 2;
				auto c = min_cost_max_flow(nodes, use_capacities, mid + 1) - min_cost_max_flow(nodes, use_capacities, mid) + b * (int)use_hall.size();
				if (c < 0) {
					left = mid + 1;
				}
				else {
					right = mid;
				}
			}
			auto c = min_cost_max_flow(nodes, use_capacities, right);
			if (min > c + right * b * use_hall.size() + sum_fee) {
				min = c + right * b * use_hall.size() + sum_fee;
			}
		}
	}
	std::cout << min << std::endl;
	solve();
}
int main() {
	solve();
}
accuracy: 1
time_ms: 3130
memory_kb: 3248
final_rank: 2

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define NUM 150

struct Info{
	int x,y,capacity,fee;
};


//辺を表す構造体{行先、容量、コスト、逆辺のインデックス}
struct Edge{
	Edge(int arg_to,int arg_capacity,int arg_cost,int arg_rev_index){
		to = arg_to;
		capacity = arg_capacity;
		cost = arg_cost;
		rev_index = arg_rev_index;
	}

	int to,capacity,cost,rev_index;
};

int N,M,B;
int V; //頂点数
int POW[6];
vector<Edge> G[NUM]; //グラフの隣接リスト表現
int dist[NUM]; //最短距離
int pre_node[NUM],pre_edge[NUM]; //直前の頂点と辺
Info student[100],house[5];


//fromからtoへ向かう容量capacity,コストcostの辺をグラフに追加する
void add_edge(int from,int to,int capacity,int cost){
	G[from].push_back(Edge(to,capacity,cost,G[to].size()));
	G[to].push_back(Edge(from,0,-cost,G[from].size()-1));
}

//sourceからsinkへの、流量flowの最小費用流を求める
//流せない場合は-1を返す
int min_cost_flow(int source,int sink,int flow){
	int ret = 0;
	while(flow > 0){
		//ベルマンフォード方により、source-sink間最短経路を求める
		for(int i = 0; i < V; i++)dist[i] = BIG_NUM;
		dist[source] = 0;
		bool update = true;
		while(update){
			update = false;
			for(int node_id = 0; node_id < V; node_id++){
				if(dist[node_id] == BIG_NUM)continue;
				for(int i = 0; i < G[node_id].size(); i++){
					Edge &e = G[node_id][i];
					if(e.capacity > 0 && dist[e.to] > dist[node_id]+e.cost){
						dist[e.to] = dist[node_id]+e.cost; //node_idを経由した方が早い場合
						pre_node[e.to] = node_id;
						pre_edge[e.to] = i;
						update = true;
					}
				}
			}
		}

		if(dist[sink] == BIG_NUM){
			//これ以上流せない
			return -1;
		}

		//source-sink間最短路に沿って目いっぱい流す
		int tmp_flow = flow;
		for(int node_id = sink; node_id != source; node_id = pre_node[node_id]){
			tmp_flow = min(tmp_flow,G[pre_node[node_id]][pre_edge[node_id]].capacity);
		}

		flow -= tmp_flow;
		ret += tmp_flow*dist[sink];
		for(int node_id = sink; node_id != source; node_id = pre_node[node_id]){
			Edge &e = G[pre_node[node_id]][pre_edge[node_id]];
			e.capacity -= tmp_flow;
			G[node_id][e.rev_index].capacity += tmp_flow;
		}
	}
	return ret;
}

void func(){

	for(int i = 0; i < N; i++){
		scanf("%d %d",&student[i].x,&student[i].y);
	}

	for(int i = 0; i < M; i++){
		scanf("%d %d %d %d",&house[i].x,&house[i].y,&house[i].capacity,&house[i].fee);
	}

	int ans = BIG_NUM;
	vector<int> HOUSE;

	int left,right,m;
	int cap_sum,fee_sum,house_num;
	int tmp_min,result1,result2;
	int source,sink;

	for(int state = 1; state < POW[M]; state++){

		HOUSE.clear();

		cap_sum = 0,fee_sum = 0,house_num = 0;
		for(int loop = 0; loop < M; loop++){
			if(state & (1 << loop)){
				cap_sum += house[loop].capacity;
				fee_sum += house[loop].fee;
				HOUSE.push_back(loop);
				house_num++;
			}
		}

		if(cap_sum < N)continue; //そもそもN人収容できなければSKIP

		//Dの仮定値
		left = 0,right = 4000,m = (left+right)/2;
		tmp_min = BIG_NUM;

		source = 0,sink = N+house_num+1,V = N+house_num+2;

		while(left <= right){

			//D == m+1の時の金額を求める
			for(int i = 0; i < NUM; i++)G[i].clear();

			for(int i = 1; i <= N; i++){
				add_edge(source,i,1,0); //sourceから各生徒に辺を張る
			}

			for(int i = N+1; i <= N+house_num; i++){
				add_edge(i,sink,house[HOUSE[i-(N+1)]].capacity,0); //各会場からsinkへエッジを張る
			}

			for(int i = 1; i <= N; i++){ //各生徒から会場へ辺を張る
				for(int k = N+1; k <= N+house_num; k++){
					add_edge(i,k,1,max(0,abs(student[i-1].x-house[HOUSE[k-(N+1)]].x)
							+abs(student[i-1].y-house[HOUSE[k-(N+1)]].y)-(m+1)));
				}
			}



			result1 = min_cost_flow(source,sink,N);
			result1 += fee_sum + (m+1)*B*house_num; //会場使用料+シャトルバスの使用料を加算

			//D == mの時の金額を求める

			for(int i = 0; i < NUM; i++)G[i].clear();

			for(int i = 1; i <= N; i++){
				add_edge(source,i,1,0); //sourceから各生徒に辺を張る
			}

			for(int i = N+1; i <= N+house_num; i++){
				add_edge(i,sink,house[HOUSE[i-(N+1)]].capacity,0); //各会場からsinkへエッジを張る
			}

			for(int i = 1; i <= N; i++){ //各生徒から会場へ辺を張る
				for(int k = N+1; k <= N+house_num; k++){
					add_edge(i,k,1,max(0,abs(student[i-1].x-house[HOUSE[k-(N+1)]].x)
							+abs(student[i-1].y-house[HOUSE[k-(N+1)]].y)-m));
				}
			}

			result2 = min_cost_flow(source,sink,N);
			result2 += fee_sum + m*B*house_num;

			tmp_min = min(tmp_min,min(result1,result2));

			if(result1 >= result2){ //Dの仮定値が最適値以上
				right = m-1; //より小さく
			}else{
				left = m+1;
			}
			m = (left+right)/2;
		}

		ans = min(ans,tmp_min);
	}

	printf("%d\n",ans);

}

int main(){

	for(int i = 0; i < 6; i++)POW[i] = pow(2,i);

	while(true){
		scanf("%d %d %d",&N,&M,&B);
		if(N == 0 && M == 0 && B == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 2530
memory_kb: 3444
final_rank: 6

code_snippet: #include<bits/stdc++.h>
int INF = (1<<20);
using namespace std;

struct edge{
    int to,pnt,cost,rev;
    edge(int to,int pnt,int cost,int rev)
        :to(to),pnt(pnt),cost(cost),rev(rev){}
};

int MAX_V=222;
int S=MAX_V-2,T=MAX_V-1; 
int N,M,B;
int ax[111],ay[111];
int bx[5],by[5];
int c[5],f[5];
vector<edge> G[222];
int dist[222];
int prevv[222],preve[222];

int min_cost_flow(int f){
  int ret = 0;
  while(f > 0){
    fill_n(dist,MAX_V,INF);
    dist[S] = 0;
    bool update = true;
    while(update){
      update = false;
      for(int v = 0; v < MAX_V;v++){
    if(dist[v] == INF) continue;
    for(int i=0;i<G[v].size();i++){
      edge &e = G[v][i];
      if(e.pnt > 0 && dist[e.to] > dist[v] + e.cost){
        dist[e.to] = dist[v] + e.cost;
        prevv[e.to] = v;
        preve[e.to] = i;
        update = true;
      }
    }
      }
    }
    if(dist[T] == INF) return -1;
    int d = f;
    for(int v=T;v!=S;v=prevv[v]){
      d = min(d,G[prevv[v]][preve[v]].pnt);
    }
    f -= d;
    ret += d * dist[T];
    for(int v=T;v!=S;v=prevv[v]){
      edge &e = G[prevv[v]][preve[v]];
      e.pnt -= d;
      G[v][e.rev].pnt += d;
    }
  }
  return ret;
}

void add_edge(int from,int to,int pnt,int cost){
  G[from].push_back(edge(to,pnt,cost,G[to].size()));
  G[to].push_back(edge(from,0,-cost,G[from].size()-1));
}

void make_edge(int bit,int mid){
  fill_n(G,MAX_V,vector<edge>());
  for(int i=0;i<N;i++){
    add_edge(S,i,1,0);
    for(int j=0;j<M;j++){
      if((bit>>j&1)==0)continue;
      int d = abs(ax[i]-bx[j])+abs(ay[i]-by[j]);
      add_edge(i,N+j,1,max(0,d-mid));
    }
  }
  for(int i=0;i<M;i++){
    if((bit>i&1)==0)continue;
    add_edge(N+i,T,c[i],0);
  }
}

int search(int bit){
  int ret=0,cnt=0;
  for(int i=0;i<M;i++){
    if(bit&(1<<i)){
      ret += f[i];
      cnt++;
    }
  }
  int left=0,right=100000;
  while(right-left > 1){
    int mid = (left+right)/2;
    make_edge(bit,mid);
    int tmp1 = min_cost_flow(N)+mid*B*cnt;
    make_edge(bit,mid-1);
    int tmp2 = min_cost_flow(N)+(mid-1)*B*cnt;
    if(tmp1 == -1 || tmp2 == -1) return INF;
    if(tmp1 < tmp2) left = mid;
    else right = mid;
  }
  make_edge(bit,left);
  return ret+min_cost_flow(N)+left*B*cnt;
}

int main(){
  while(cin >> N >> M >> B, N) {
    for(int i=0;i<N;i++) cin >> ax[i] >> ay[i];
    for(int i=0;i<M;i++) cin >> bx[i] >> by[i] >> c[i] >> f[i];
    int ans = INF;
    for(int i=1;i<(1<<M);i++){
      ans = min(ans,search(i));
    }
    cout << ans << endl;
  }
}
accuracy: 1
time_ms: 3790
memory_kb: 3136
final_rank: 1