LG1772 [ZJOI2006] 物流运输 dp+最短路
题意简述
问题分析
这一题乍一看没有什么头绪。
考虑设 \(f(i)\) 代表到第 \(i\) 天结束,所花费的最小费用。
记 \(C_{S,T}\) 代表从第 \(S\) 天到第 \(T\) 天走同一条最短路的花费,暴力标记掉 \([S,T]\) 范围内任意一天不可走的点。
所有的 \(C_{S,T}\) 是可以通过跑 \(n^2\) 次最短路求出来的。
这样显然有 \(f(i) = \min\limits_{j=1}^{i-1}{f(j)+C_{j+1,i} \times (i - j) + k}\)
预处理要把 \(f(i)\) 赋值为 \(C_{1,i} \times i\)。
时间复杂度应该是 \(O(n^3 d \log n)\)
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
template < typename Tp >
void read(Tp &x) {
x = 0; int fh = 1; char ch = 1;
while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if(ch == '-') fh = -1, ch = getchar();
while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
x *= fh;
}
const int maxe = 2000 + 7;
const int maxn = 100 + 7;
int n, m, k, e, d;
int Head[maxn], to[maxe], Next[maxe], tot, w[maxe];
void add(int x, int y, int z) {
to[++tot] = y, Next[tot] = Head[x], Head[x] = tot, w[tot] = z;
}
int Cos[maxn][maxn];
int dis[maxn];
bool inq[maxn];
priority_queue <pair <int, int> > Q;
bool ok[maxn];
void dijkstra(void) {
memset(dis, 0x3f, sizeof(dis));
dis[1] = 0; Q.push(make_pair(0, 1));
memset(inq, false, sizeof(inq));
while(Q.size()) {
int x = Q.top().second; Q.pop();
if(inq[x]) continue; inq[x] = true;
for(int i = Head[x]; i; i = Next[i]) {
int t = to[i]; if(ok[t]) continue;
if(dis[t] > dis[x] + w[i]) {
dis[t] = dis[x] + w[i];
Q.push(make_pair(-dis[t], t));
}
}
}
}
int p[maxn], L[maxn], R[maxn];
void Init(void) {
read(n); read(m); read(k); read(e);
for(int i = 1, x, y, z; i <= e; i++) {
read(x); read(y); read(z);
add(x, y, z); add(y, x, z);
}
read(d);
for(int i = 1; i <= d; i++) {
read(p[i]); read(L[i]); read(R[i]);
}
}
void mark(int S, int T) {
memset(ok, false, sizeof(ok));
for(int i = 1; i <= d; i++) {
if(L[i] > T || R[i] < S) continue;
ok[p[i]] = true;
}
}
LL dp[maxn];
void Work(void) {
for(int S = 1; S <= n; S++) {
for(int T = S; T <= n; T++) {
mark(S, T);
dijkstra();
Cos[S][T] = dis[m];
}
}
memset(dp, 0x3f, sizeof(dp));
for(int i = 1; i <= n; i++) {
if(Cos[1][i] != 0x3f3f3f3f) dp[i] = Cos[1][i] * i;
}
for(int i = 2; i <= n; i++) {
for(int j = 1; j < i; j++) {
if(Cos[j + 1][i] != 0x3f3f3f3f) {
dp[i] = min(dp[i], dp[j] + Cos[j + 1][i] * (i - j) + k);
}
}
}
printf("%lld\n", dp[n]);
}
int main(void) {
Init();
Work();
return 0;
}