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;
}
posted @ 2022-07-20 18:02  览遍千秋  阅读(35)  评论(0编辑  收藏  举报