1. 程式人生 > >2018-2019 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2018) D. Delivery Delays 二分+最短路+DP

2018-2019 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2018) D. Delivery Delays 二分+最短路+DP

題目連結:https://codeforc.es/gym/101933/problem/D

題意:地圖上有 n 個位置和 m 條邊,每條邊連線 u、v 且有一個距離 w,一共有 k 個詢問,每個詢問表示 ti 時間在位置 ui 有人下單點了披薩,而披薩店在 di 時間做好披薩可以送出去,披薩店在位置 1,送披薩必須按順序送,問客人從下單到拿到披薩的最長等待時間最短是多少。

題解:首先可以對每個點跑一次 dij,預處理出每兩點之間的最短路,然後考慮二分答案,判斷是否合法。dp[i][j]代表已經送完前 i 個位置,且拿了前 j 個位置的披薩的最小時間,還需要一維 k,0 表示送完以後當前在第 i 個點披薩的位置,1 表示當前在披薩店,然後進行轉移即可。

 

  1 #include <bits/stdc++.h>
  2 #define sd(a) scanf("%d",&a)
  3 #define mst(a,b) memset(a,b,sizeof a)
  4 #define mp make_pair
  5 typedef long long ll;
  6 #define pb push_back
  7 using namespace std;
  8 typedef pair<int, int> pii;
  9 const int maxn = 2e5 + 10;
 10 //int inf = 0x3f3f3f3f;
11 const int mod = 1000000007; 12 ll dis[1111][1111]; 13 vector<pii>g[1111]; 14 bool vis[1111]; 15 void dij(int s, int n) { 16 ll inf2 = 1e16; 17 for(int i = 1; i <= n; ++i) 18 dis[s][i] = inf2, vis[i] = 0; 19 dis[s][s] = 0; 20 priority_queue<pair<ll, int> >q;
21 q.push(mp(0, s)); 22 for(; !q.empty();) { 23 int u = q.top().second; 24 q.pop(); 25 if(vis[u]) 26 continue; 27 vis[u] = 1; 28 for(int j = 0, sz = g[u].size(); j < sz; ++j) { 29 int v = g[u][j].first; 30 int w = g[u][j].second; 31 if(dis[s][v] > dis[s][u] + w) { 32 dis[s][v] = dis[s][u] + w; 33 q.push(mp(-dis[s][v], v)); 34 } 35 } 36 } 37 } 38 int s[1111], to[1111], t[1111]; 39 ll dp[1111][1111][2]; 40 bool check(ll x, int n, int k) { 41 ll inf2 = 1e16; 42 for(int i = 0; i <= k; ++i) 43 for(int j = 0; j <= k; ++j) 44 dp[i][j][0] = dp[i][j][1] = inf2; 45 dp[0][0][1] = 0; 46 for(int i = 0; i < k; ++i) { 47 for(int j = i; j <= k; ++j) { 48 for(int o = 0; o < 2; ++o) { 49 if(dp[i][j][o] == inf2) 50 continue; 51 if(!o) { 52 dp[i][j][1] = min(dp[i][j][1], dp[i][j][0] + dis[to[i]][1]); 53 if(j > i && i < k) { 54 ll time = dp[i][j][0] + dis[to[i]][to[i + 1]]; 55 if(s[i + 1] + x >= time) 56 dp[i + 1][j][0] = min(dp[i + 1][j][0], time); 57 } 58 } else { 59 if(j < k) 60 dp[i][j + 1][1] = min(dp[i][j + 1][1], max(dp[i][j][1], (ll)t[j + 1]) ); 61 if(i < k && j >= i + 1) { 62 ll time = dp[i][j][1] + dis[1][to[i + 1]]; 63 if(s[i + 1] + x >= time) 64 dp[i + 1][j][0] = min(dp[i + 1][j][0], time); 65 } 66 } 67 } 68 } 69 } 70 return dp[k][k][0] != inf2; 71 } 72 73 int main() { 74 #ifdef local 75 freopen("in", "r", stdin); 76 #endif // local 77 int n, m; 78 sd(n), sd(m); 79 for(int i = 1; i <= m; ++i) { 80 int u, v, w; 81 sd(u), sd(v), sd(w); 82 g[u].pb(mp(v, w)); 83 g[v].pb(mp(u, w)); 84 } 85 int k; 86 sd(k); 87 to[0] = 1; 88 for(int i = 1; i <= k; ++i) 89 sd(s[i]), sd(to[i]), sd(t[i]); 90 for(int i = 1; i <= n; ++i) 91 dij(i, n); 92 ll ans = 1e16; 93 ll l = 0, r = ans; 94 for(; l <= r;) { 95 ll mid = (l + r) >> 1; 96 if(check(mid, n, k)) 97 ans = mid, r = mid - 1; 98 else 99 l = mid + 1; 100 } 101 printf("%lld\n", ans); 102 return 0; 103 }