[Luogu P1772] [BZOJ 1003] [ZJOI2006]物流运输

洛谷传送门
BZOJ传送门

题目描述

物流公司要把一批货物从码头 A A A运到码头 B B B。由于货物量比较大,需要 n n n天才能运完。货物运输过程中一般要转停好几个码头。物流公司通常会设计一条固定的运输路线,以便对整个运输过程实施严格的管理和跟踪。由于各种因素的存在,有的时候某个码头会无法装卸货物。这时候就必须修改运输路线,让货物能够按时到达目的地。但是修改路线是—件十分麻烦的事情,会带来额外的成本。因此物流公司希望能够订一个n天的运输计划,使得总成本尽可能地小。

输入输出格式

输入格式:

第一行是四个整数 n ( l ≤ n ≤ 100 ) n(l≤n≤100) n(ln100) m ( l ≤ m ≤ 20 ) m(l≤m≤20) m(lm20) K K K e e e n n n表示货物运输所需天数, m m m表示码头总数, K K K表示每次修改运输路线所需成本, e e e表示航线条数。接下来 e e e行每行是一条航线描述,包括了三个整数,依次表示航线连接的两个码头编号以及航线长度( &gt; 0 &gt;0 >0)。其中码头 A A A编号为 1 1 1,码头 B B B编号为 m m m。单位长度的运输费用为 1 1 1。航线是双向的。再接下来一行是一个整数 d d d,后面的 d d d行每行是三个整数 P ( 1 &lt; P &lt; m ) P(1&lt;P&lt;m) P(1<P<m) a a a b ( 1 ≤ a ≤ b ≤ n ) b(1≤a≤b≤n) b(1abn)。表示编号为 P P P的码头从第 a a a天到第 b b b天无法装卸货物(含头尾)。同一个码头有可能在多个时间段内不可用。但任何时间都存在至少一条从码头 A A A到码头 B B B的运输路线。

输出格式:

包括了一个整数表示最小的总成本。总成本= n n n天运输路线长度之和+ K K K*改变运输路线的次数。

输入输出样例

输入样例#1:
  5 5 10 8
  1 2 1
  1 3 3
  1 4 2
  2 3 2
  2 4 4
  3 4 1
  3 5 2
  4 5 2
  4
  2 2 3
  3 1 1
  3 3 3
  4 4 5
输出样例#1:
32

说明

【样例输入说明】

img

上图依次表示第 1 1 1至第 5 5 5天的情况,阴影表示不可用的码头。

【样例输出说明】

前三天走 1 − 4 − 5 1-4-5 145,后两天走 1 − 3 − 5 1-3-5 135,这样总成本为 ( 2 + 2 ) ∗ 3 + ( 3 + 2 ) ∗ 2 + 10 = 32 (2+2)*3+(3+2)*2+10=32 (2+2)3+(3+2)2+10=32

解题分析

m m m范围如此小, 显然我们可以直接每次求出最短路大力 d p dp dp

我们在第 i i i天显然有两个抉择: 更换成新的路径, 或从第 j j j天开始就走一样的最短路。

这样我们就很好写出 d p dp dp转移方程了: d p [ i ] = m i n j = 1 i ( d p [ j − 1 ] + ( i − j + 1 ) × l e n 1 → m + k ) dp[i]=min_{j=1}^{i}(dp[j-1]+(i-j+1)\times len_{1\to m}+k) dp[i]=minj=1i(dp[j1]+(ij+1)×len1m+k), 初始状态为 d p [ 0 ] = − k dp[0]=-k dp[0]=k(因为显然多算了一次更换最短路的费用)。

代码如下:

#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#define R register
#define IN inline
#define W while
#define MX 25
#define gc getchar()
#define ll long long
template <class T>
IN void in(T &x)
{
    x = 0; R char c = gc;
    for (; !isdigit(c); c = gc);
    for (;  isdigit(c); c = gc)
    x = (x << 1) + (x << 3) + c - 48;
}
int dot, day, line, cnt, del;
int head[MX], out[MX], stat[MX][105];
ll dis[MX], dp[105];
bool inq[MX];
struct Edge {int to, len, nex;} edge[MX << 4];//??
std::queue <int> q;
IN void add(R int from, R int to, R int len)
{edge[++cnt] = {to, len, head[from]}, head[from] = cnt;}
IN ll SPFA()
{
    std::memset(dis, 63, sizeof(dis));
    dis[1] = 0; R int now, i; q.push(1);
    W (!q.empty())
    {
        now = q.front(); q.pop();
        for (i = head[now]; i; i = edge[i].nex)
        {
            if(out[edge[i].to] || dis[edge[i].to] <= dis[now] + edge[i].len) continue;
            dis[edge[i].to] = dis[now] + edge[i].len;
            if(!inq[edge[i].to]) q.push(edge[i].to), inq[edge[i].to] = true;
        }
        inq[now] = false;
    }
    return dis[dot];
}
int main(void)
{
    int a, b, c, buf;
    R int i, j, k;
    ll res;
    in(day), in(dot), in(del), in(line);
    std::memset(dp, 63, sizeof(dp)); dp[0] = -del;
    for (i = 1; i <= line; ++i)
    in(a), in(b), in(c), add(a, b, c), add(b, a, c);
    in(buf);
    for (i = 1; i <= buf; ++i)
    {
        in(a), in(b), in(c);
        for (j = b; j <= c; ++j) stat[a][j] = true;
    }
    for (i = 1; i <= day; ++i)
    {
        std::memset(out, 0, sizeof(out));
        for (j = i; j; --j)
        {
            for (k = 1; k <= dot; ++k)
            out[k] |= stat[k][j];
            res = SPFA();
            if(res == dis[0]) continue;
            dp[i] = std::min(dp[i], dp[j - 1] + 1ll * (i - j + 1) * res + del); 
        }
    }
    printf("%lld", dp[day]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值