【PGBATTLE2019_ましゅまろ4】ラッシュアワー
[Q] https://products.sint.co.jp/hubfs/resource/topsic/pgb/1-4.pdf
ダイクストラ。待ち時間のabsをうまく場合分けさえできればと思う。
これは、initの時点で、
D-|T-t| > K の t について。
-|T-t| > K-D
|T-t| <= D-K
|t-T| <= D-K
K-D <= t-T <= D-K
K-D+T <= t <= D-K+T
int left = -1, right = -1;
if (K-D <= D-K) {
left = K-D+T;
right = D-K+T;
}
「left ~ rightの時間の間は通行できない」の時間管理を抑えればわかりやすかったかもしれない。
dijkstraの中でabsを処理するなら以下。
// D-abs(T-t)<=K なら、その道を通ってok、
を整理する。
abs(T- t) > D - K が だめ だとわかる。
D-abs(T-t)は、tを動かすと、へ、の字の動きをする。折り返しがあるなら、t は折り返し分の距離 abs(T-t)*2を、即座に足してしまっていい。
for(auto e : G[v]){ //e=next, cost
// D-abs(T-t)<=K ならok
// -abs(T-t)<=K-D
// abs(T-t)>D-K
// abs(T-cost)>konz-K ならok
ll add = 0;
if (abs(T-d[v]) <= e.konz-K){ // だめ
if (T>d[v]) add = (T-d[v])*2; // 混雑度があがっていく おりかえす
add += (e.konz-K) - abs(T-d[v]);
}
if (d[e.to] > d[v] + e.cost + add){
d[e.to] = d[v] + e.cost + add;
que.push(P(d[e.to], e.to));
prev[e.to] = v; //vからe.toについた
実装
struct edge{ll to, cost, konz;};
typedef pair<ll, ll> P;
ll N, M, T, K;
struct graph{
ll V;
vector<vector<edge>> G;
vector<ll> d;
vector<ll> prev;
vector<bool> used;
graph(ll n){
init(n);
}
void init(ll n){
V = n;
G.resize(V);
d.resize(V);
prev.resize(V);
used.resize(n);
rep(i, n) used[i] = false;
}
void add_edge(ll s, ll t, ll cost, ll konz){
edge e;
e.to = t, e.cost = cost;
e.konz = konz;
G[s].push_back(e);
}
void del_edge(ll s, ll t, ll cost){
for (auto it = G[s].begin(); it != G[s].end();){
if ((*it).to == t && (*it).cost == cost)
it = G[s].erase(it);
else
it++;
}
}
ll get_edgesize(ll s){
ll size = 0;
for(auto v: G[s]){
if (used[v.to]) continue;
used[v.to] = true;
size++;
size += get_edgesize(v.to);
}
return size;
}
//経路はprevに
void dijkstra(ll s){
rep(i, V){
d[i] = oo;
prev[i] = -1;
}
d[s] = 0;
priority_queue<P, vector<P>, greater<P>> que;
que.push(P(0, s)); //cost, v
while(!que.empty()){
P p = que.top(); que.pop();
ll v = p.second;
if(d[v] < p.first) continue;
for(auto e : G[v]){ //e=next, cost
// D-abs(T-t)<=K
// -abs(T-t)<=K-D
// abs(T-t)>D-K
// abs(T-cost)>konz-Kならok
ll add = 0;
if (abs(T-d[v]) <= e.konz-K){ // だめ
if (T>d[v]) add = (T-d[v])*2; // 混雑度があがっていく おりかえす
add += (e.konz-K) - abs(T-d[v]);
}
if (d[e.to] > d[v] + e.cost + add){
d[e.to] = d[v] + e.cost + add;
que.push(P(d[e.to], e.to));
prev[e.to] = v; //vからe.toについた
}
}
}
}
vector<ll> get_path(int g, int s) {
// s 1->2->3 g
// path[0]=1 path[1]=2 path[2]=3 を返す
vector<ll> path;
for (int cur = g; cur != s; cur = prev[cur]) { // goalまで
path.push_back(cur);
}
path.push_back(s);
reverse(path.begin(), path.end()); // 逆順なのでひっくり返す
return path;
}
};
int main(){
cincout();
cin >> N >> M >> T >> K;
graph g(N+1); // 0index ~
// 戻り道
rep(i, M){
ll A, B, C, D;
cin >> A >> B >> C >> D;
--A, --B;
g.add_edge(B, A, C, D);
g.add_edge(A, B, C, D);
}
g.dijkstra(0);
if (g.d[N-1] == oo)
cout << -1 << endl;
else
cout << g.d[N-1] << endl;
}
もしくは left ~ rightでとる場合
void dijkstra(ll s){
rep(i, V){
d[i] = oo;
prev[i] = -1;
}
d[s] = 0;
priority_queue<P, vector<P>, greater<P>> que;
que.push(P(0, s)); //cost, v
while(!que.empty()){
P p = que.top(); que.pop();
ll v = p.second;
if(d[v] < p.first) continue;
for(auto e : G[v]){ //e=next, cost
ll nx = d[v]+e.cost;
if (d[v] < e.right && nx > e.left) chmax(nx, e.right+e.cost);
if(d[e.to] > nx){
d[e.to] = nx;
que.push(P(d[e.to], e.to));
prev[e.to] = v; //vからe.toについた
}
}
}
}
int main(){
cin.tie(0);
ios::sync_with_stdio(0);
cout << fixed << setprecision(10);
ll N, M, T, K;
cin >> N >> M >> T >> K;
graph g(N+1); // 0index ~
// 戻り道
rep(i, M){
ll A, B, C, D;
cin >> A >> B >> C >> D;
--A, --B;
// D-|T-t| > K のtについて。
// |T-t| <= D-K
// |t-T| <= D-K
// K-D <= t-T <= D-K
// K-D+T <= t <= D-K+T
ll left=-1, right=-1;
if (K-D <= D-K){
left = K-D+T;
right = D-K+T;
}
g.add_edge(A, B, C, left, right);
g.add_edge(B, A, C, left, right);
}
g.dijkstra(0);
if (g.d[N-1] == oo)
cout << -1 << endl;
else
cout << g.d[N-1] << endl;
}
この記事が気に入ったらサポートをしてみませんか?