1003: [ZJOI2006]物流運輸[最短路+dp]
阿新 • • 發佈:2018-11-07
題意:存在有m個碼頭,修改運輸成本k,以及e條路,讓設計一條n天的路線,使得花費最小,每一條路線都是從頭跑到尾。
題解:我們可以先到設計
表示從第一天到第
天的最小花費,
表示第
天到第
天從1->n的最短路是多少,通過dijkstra或者spfa都能跑出來,需要標記在
天內哪些碼頭能用,然後通過dp來轉移,轉移方程如下:
表示轉了路線一次,剩下的
天走
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define g getchar()
#define rep(i, a, b) for(int i = a; i <= b; i++)
#define per(i, a, b) for(int i = a; i >= b; i--)
#define met(a, b) memset(a, b, sizeof(a))
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
inline int read() {
int res = 0, f = 1; char ch = g;
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = g;}
while(ch >= '0' && ch <= '9') {res = res * 10 + ch - '0'; ch = g;}
return res;
}
struct Edge {
int to, next, val;
} e[maxn];
int h[maxn], d, n, k, m, cnt;
ll f[200], t[200][200];
int flag[200][200];
void add(int u, int v, int w) {
e[cnt].to = v;
e[cnt].val = w;
e[cnt].next = h[u];
h[u] = cnt++;
}
int spfa(int l, int r) {
int lim[maxn], vis[maxn], dis[maxn];
met(lim, 0);
met(vis, 0);
for(int i = 1; i <= n; i++) dis[i] = inf;
rep(i, 1, n) rep(j, l, r) if(flag[i][j]) lim[i] = 1;
queue<int> q;
q.push(1);
dis[1] = 0;
vis[1] = 1;
while(!q.empty()) {
int u = q.front();
q.pop();
for(register int i = h[u]; ~i; i = e[i].next) {
int v = e[i].to;
if(!lim[v] && dis[v] > dis[u] + e[i].val) {
dis[v] = dis[u] + e[i].val;
if(!vis[v]) {
vis[v] = 1;
q.push(v);
}
}
}
vis[u] = 0;
}
return dis[n];
}
int main() {
met(h, -1);
cnt = 0;
d = read(); n = read(); k = read(); m = read();
int u, v, w;
rep(i, 1, m) {
u = read(), v = read(), w = read();
add(u, v, w); add(v, u, w);
}
int x = read();
int l, r, p;
while(x--) {
p = read(), l = read(), r = read();
for(register int i = l; i <= r; i++) flag[p][i] = 1;
}
rep(i, 1, d) rep(j, 1, d) t[i][j] = spfa(i, j);
rep(i, 1, d) {
f[i] = (ll)t[1][i] * (ll)i;
rep(j, 0, i) {
f[i] = min(f[i], k + f[j] + t[j + 1][i] * (i - j));
}
}
printf("%lld\n", f[d]);
return 0;
}