UTPC2013 H Asteroids2
問題
日本語なので本文参照(http://utpc2013.contest.atcoder.jp/tasks/utpc2013_08)
NxNの二次元グリッドに石がM個ある。
i番目の石は(x[i], y[i])にあって、強さの和がa[i]以上b[i]以下になるようレーザーを当てる。
レーザーはx軸に平行またはy軸に平行な直線にそってしか撃てない。
x = kに撃てるレーザーの強さは0以上p[k]以下、
y = kに撃てるレーザーの強さは0以上q[k]以下。
軸にそって撃ったレーザーは直線上にある全ての石を貫通して当たる。
このとき全ての石に制約を満たすように当てるレーザーの当て方があるかどうかを判定せよ。
制約条件
N≦1000
M≦10^5
p[i], q[i]≦10^6
a[i], b[i]≦2*10^6
方針
どうみても牛ゲー。
制約を不等式で書く。x = iで発射するレーザーの強さをxi,
y = iで発射するレーザーの強さをyiとする。
0≦xi≦p[i], 0≦yi≦q[i]
j番目の石について、a[j]≦x_x[j] + y_y[j]≦b[j]
で、牛ゲー化するためには、不等式が全て
xi - xj ≦ const
の形をしていなければならないが、
ゼロの変数を導入するのと、
yi = -x_(i + N)というようにおけば牛ゲーになる。
牛ゲー不等式に変換したら、そのグラフを作る。
iからjに辺があるとき最短距離はd[j]≦d[i] + e[i][j]を満たすので、
要するに上の式だとjからiにconstの辺を張ればいい。
このグラフに負のループがなければ制約を満たす解が存在する。
Bellman-Fordのアルゴリズムを使えばO(VE)とかなので間に合う。
なんか間に合わなかったので更新がなくなるかループ検出したら即終了としたら間に合った。
#define F first #define S second const int N = 1000; int n, m, p[N], q[N], zero; ll dist[2 * N + 1]; vector<pair<pi, int> > es; int main(){ scanf("%d%d", &n, &m); zero = 2 * n; rep(i, n){ scanf("%d", p + i); es.pb(mp(mp(zero, i), p[i])); es.pb(mp(mp(i, zero), 0)); } rep(i, n){ scanf("%d", q + i); es.pb(mp(mp(i + n, zero), q[i])); es.pb(mp(mp(zero, i + n), 0)); } rep(i, m){ int x, y, a, b; scanf("%d%d%d%d", &x, &y, &a, &b); x--; y--; es.pb(mp(mp(y + n, x), b)); es.pb(mp(mp(x, y + n), -a)); } rep(i, 2 * n) dist[i] = inf; rep(it, 2 * n + 2){ bool update = 0; rep(i, es.size()){ int a = es[i].F.F, b = es[i].F.S, c = es[i].S; if(dist[a] < inf && dist[b] > dist[a] + c){ dist[b] = dist[a] + c; update = 1; if(it == 2 * n + 1){ cout << "no" << endl; return 0; } } } if(dist[0] < 0){ cout << "no" << endl; return 0; } if(!update) break; } rep(i, 2 * n + 1) cerr<<dist[i]<<endl; cout << "yes" << endl; return 0; }