题意:
有 m 个公交车站,共开通了 n 1 + n 2 n_1 + n_2 n1+n2 趟公交,前 n 1 n_1 n1 趟公交从 1 号一直开到 n 号,后 n 2 n_2 n2 趟公交从 n 号一直开到 1 号,记 x i , j x_{i, j} xi,j 为第 j 趟公交抵达第 i 号车站的时间,假设公交车停靠时间极短。现在 t1 时刻你在第 s 号车站,在 t2 时刻会等到朋友,期间你希望尽可能在公交车上坐着,当然,最后要在 t2 时刻前回来 s 号车站,问等候朋友期间不在公交车上的可能的最少时间。( m ∗ ( n 1 + n 2 ) < = 1 e 6 , t 1 , t 2 , x i , j < = 1 e 9 m * (n_1 + n_2) <= 1e6, t_1, t_2, x_{i, j} <= 1e9 m∗(n1+n2)<=1e6,t1,t2,xi,j<=1e9)
链接:
https://cometoj.com/contest/71/problem/C?problem_id=4018
解题思路:
这一看就很最短路。 考虑如何建图,显然每趟公交在每个车站最多被搭乘一次,因此可以 <公交编号,车站编号> 建点。对于每一趟公交,按行驶方向连权为 0 的有向边;对于同一车站停靠的不同公交,按时间升序连权为等待时间的有向边(注意存在不同公交在同一时刻停靠,此时它们之间应当连无向边)。最后,起点终点分别连上可搭乘的公交,跑最短路即可。
参考代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e6 + 5;
const int maxm = 1e6 + 5;
const int mod = 1e9 + 7;
//const int inf = 0x3f3f3f3f;
const ll inf = 0x3f3f3f3f3f3f3f3f;
typedef pair<ll, int> pli;
priority_queue<pli, vector<pli>, greater<pli> > q;
vector<pli> G[maxn];
vector<pii> wi[maxn];
ll dis[maxn];
int m, n1, n2, sp, tp, t1, t2, n;
inline int getId(int x, int y){
return (x - 1) * (n1 + n2) + y;
}
inline int check(int t){
return t >= t1 && t <= t2;
}
void build(){
for(int i = 1; i < m; ++i){
for(int j = 1; j <= n1; ++j){
int u = wi[i][j].second, v = wi[i + 1][j].second;
if(check(wi[i][j].first) && check(wi[i + 1][j].first)) G[u].pb({0, v});
}
}
for(int i = 2; i <= m; ++i){
for(int j = n1 + 1; j <= n; ++j){
int u = wi[i][j].second, v = wi[i - 1][j].second;
if(check(wi[i][j].first) && check(wi[i - 1][j].first)) G[u].pb({0, v});
}
}
for(int i = 1; i <= m; ++i) sort(wi[i].begin(), wi[i].end());
for(int i = 1; i <= m; ++i){
for(int j = 1; j < n; ++j){
int u = wi[i][j].second, v = wi[i][j + 1].second;
int t1 = wi[i][j].first, t2 = wi[i][j + 1].first;
if(!check(t1) || !check(t2)) continue;
G[u].pb({t2 - t1, v});
if(t1 == t2) G[v].pb({0, u});
}
}
for(int i = 1; i < sz(wi[sp]); ++i){
int u = wi[sp][i].second, t = wi[sp][i].first;
if(check(t)) G[0].pb({t - t1, u}), G[u].pb({t2 - t, tp});
}
G[0].pb({t2 - t1, tp});
}
void dij(int s){
for(int i = 0; i <= tp; ++i) dis[i] = inf;
dis[s] = 0, q.push({dis[s], s});
while(!q.empty()){
int u = q.top().second; ll d = q.top().first; q.pop();
if(d != dis[u]) continue;
for(int i = 0; i < sz(G[u]); ++i){
int v = G[u][i].second, w = G[u][i].first;
if(dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
q.push({dis[v], v});
}
}
}
}
const int maxs = 1e3 + 5;
char buf[maxs], *p1 = buf, *p2 = buf;
inline char fr(){
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, maxs, stdin)) == p1 ? -1 : *p1++;
}
#define gc fr()
inline void read(int &x){
char ch; while(!isdigit(ch = gc)); x = ch ^ 48;
while(isdigit(ch = gc)) x = x * 10 + (ch ^ 48);
}
int main(){
// ios::sync_with_stdio(0); cin.tie(0);
int t; read(t);
while(t--){
read(m), read(n1), read(n2), read(sp), read(t1), read(t2);
n = n1 + n2, tp = m * n + 1;
for(int i = 1; i <= m; ++i){
wi[i].pb({-1, -1});
for(int j = 1; j <= n; ++j){
int w; read(w);
wi[i].pb({w, getId(i, j)});
}
}
build(), dij(0);
printf("%lld\n", dis[tp]);
for(int i = 0; i <= tp; ++i) G[i].clear();
for(int i = 1; i <= m; ++i) wi[i].clear();
}
return 0;
}