[ZJOI2006] 物流运输
题目大意:连续(n)天在一个图上走最短路,但是每个点有一定时间不开放,改变路线要加大花费,在图上走也需要花费,求最小花费。
Solution
计算出某天到某天的最短路,进行(dp)
- 状态:(f[i])表示到第(i)天的最小花费
- 转移方程:(f[i] = min{dis[1][i] cdot i, f[j - 1] + dis[j][i] cdot (i - j + 1) + k (1<j leq i)})
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
const int Maxm = 25;
const int Maxn = 105;
const int INF = 1e9;
struct Edge{
int to, next, len;
}e[20005];
int n, m, qwq, k, d, cnt, head[Maxm], ban[Maxm][Maxn], vis[Maxm], f[Maxn], dist[Maxn][Maxn], dis[Maxm];
inline void addedge(int x, int y, int z){
++cnt;
e[cnt].to = y;
e[cnt].next = head[x];
e[cnt].len = z;
head[x] = cnt;
}
inline int SPFA(int x, int y){
memset(dis, 0x3f, sizeof(dis));
memset(vis, 0, sizeof(vis));
std::queue <int> q;
q.push(1);
dis[1] = 0;
vis[1] = 1;
int u, v;
for(int i = 1; i <= m; ++i){
for(int j = x; j <= y; ++j){
if(ban[i][j]){
vis[i] = 1;
break;
}
}
}
while(!q.empty()){
u = q.front();
q.pop();
vis[u] = 0;
for(int i = head[u]; i; i = e[i].next){
v = e[i].to;
if(dis[v] > dis[u] + e[i].len){
dis[v] = dis[u] + e[i].len;
if(!vis[v]){
q.push(v);
vis[v] = 1;
}
}
}
}
return dis[m];
}
int main(){
scanf("%d %d %d %d", &n, &m, &k, &qwq);
for(int i = 1, la, lb, lc; i <= qwq; ++i){
scanf("%d %d %d", &la, &lb, &lc);
addedge(la, lb, lc);
addedge(lb, la, lc);
}//输入连接的边
scanf("%d", &d);
for(int i = 1, la, lb, lc; i <= d; ++i){
scanf("%d %d %d", &la, &lb, &lc);
for(int j = lb; j <= lc; ++j){
ban[la][j] = 1;
}
}//ban表示第la个码头第j天是否被禁止运输了
for(int i = 1; i <= n; ++i)
for(int j = i; j <= n; ++j){
dist[i][j] = SPFA(i, j);
}//计算某一天到某一天的最短距离
for(int i = 1; i <= n; ++i){
if(dist[1][i] < 1061109567)
f[i] = dist[1][i] * i;//不改变航线
else
f[i] = INF;
for(int j = 1; j <= i; ++j){
if(dist[j][i] < 1061109567)
f[i] = std::min(f[i], f[j - 1] + dist[j][i] * (i - j + 1) + k);
}//枚举上一次改变航线的日期
}
printf("%d
", f[n]);
return 0;
}