Description
物流公司要把一批货物从码头(A)运到码头(B)。由于货物量比较大,需要n天才能运完。货物运输过程中一般要转停好几个码头。物流公司通常会设计一条固定的运输路线,以便对整个运输过程实施严格的管理和跟踪。由于各种因素的存在,有的时候某个码头会无法装卸货物。这时候就必须修改运输路线,让货物能够按时到达目的地。
但是修改路线是一件十分麻烦的事情,会带来额外的成本。因此物流公司希望能够订一个(n)天的运输计划,使得总成本尽可能地小。
Input
第一行是四个整数(n(1leq nleq 100),m(1leq mleq 20),K,e)。(n)表示货物运输所需天数,(m)表示码头总数,(K)表示每次修改运输路线所需成本。
接下来(e)行每行是一条航线描述,包括了三个整数,依次表示航线连接的两个码头编号以及航线长度((>0))。其中码头(A)编号为(1),码头(B)编号为4m$。单位长度的运输费用为(1)。航线是双向的。
再接下来一行是一个整数(d),后面的(d)行每行是三个整数(P( 1 < P < m),a,b(1leq a leq b leq n))。表示编号为(P)的码头从第(a)天到第(b)天无法装卸货物(含头尾)。
同一个码头有可能在多个时间段内不可用。但任何时间都存在至少一条从码头A到码头B的运输路线。
Output
包括了一个整数表示最小的总成本。总成本=n天运输路线长度之和+K*改变运输路线的次数。
一个dp+dij最短路,难度应该达不到省选,虽然洛谷上标了蓝
由于习惯,下面(t)表示天数,(n)表示码头数,(m)表示航线数
由于不同时间内可以走的码头不同,所以最短路的统计应按时间处理
又由于(n)是极小的,所以考虑(cost(i,j)),为满足如果一个码头从第(i)到第(j)天有至少一天不能用,那么就不去用,的最短路
也就是说,(i)到(j)天,每一天的最短路都会小于等于( ext{cost}(i,j))
( ext{cost}(i,j)cdot (j-i+1))也就是(i)到(j)天一直不改变路线,所需要的最小花费,这一点下面要用到
求法就直接按定义来就行,用一个(no)数组标记每个码头是不是不能用
然后就应该用dp来处理了,设(f(i))为前(i)天的最小费用和,包括改变路线的费用
那如何转移?
枚举要在哪一天改变路线,记这个天数减(1)为(j),那么(f(i)=min(f(j)+ ext{cost}(j+1,i)cdot (i-j)+k))
那就是,从(j+1)到(i)天,以(cost(j+1,i))的费用来走,然后还要再加上一个改变路线的费用
那么,还有一种情况就是从(1)到(i)天,一直不改变路线,为了考虑这种情况,我们的(j)要从(0)开始枚举,然后(f(0)=-k),来把后面加的(k)消掉
所以可以写成式子:
(f(i)=min_{j=0}^{i-1} f(j)+ ext{cost}(j+1,i)cdot (i-j)+k)
所以答案就是(f(t)),记得除(0)以外都初始化成无穷大
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<algorithm>
#define reg register
inline int read(){
int x=0,y=1;
char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=-1;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return x*y;
}
int t,n,m,k,tot;
long long f[106],dis[26],cost[106][105];
int fir[25],to[505],nex[505],w[505];
int notcan[25][105];
int no[25],vis[25];
inline void add(int x,int y,int z){
to[++tot]=y;w[tot]=z;
nex[tot]=fir[x];fir[x]=tot;
}
std::priority_queue<std::pair<long long,int> >q;
inline int dij(){
std::memset(dis,0x3f,sizeof dis);std::memset(vis,0,sizeof vis);
q.push(std::make_pair(0,1));dis[1]=0;
while(!q.empty()){
reg int u=q.top().second;q.pop();
if(vis[u]) continue;vis[u]=1;
for(reg int v,i=fir[u];i;i=nex[i]){
v=to[i];if(no[v]) continue;
if(dis[v]>dis[u]+w[i]){
dis[v]=dis[u]+w[i];
q.push(std::make_pair(-dis[v],v));
}
}
}
return dis[n];
}
int main(){
t=read();n=read();k=read();m=read();
for(reg int x,y,z,i=1;i<=m;i++){
x=read();y=read();z=read();
add(x,y,z);add(y,x,z);
}
int tmp=read();
while(tmp--){
reg int p,a,b;
p=read();a=read();b=read();
for(reg int i=a;i<=b;i++) notcan[p][i]=1;
}
for(reg int i=1;i<=t;i++){
for(reg int j=i;j<=t;j++){
std::memset(no,0,sizeof no);
for(reg int p=1;p<=n;p++){
for(reg int kk=i;kk<=j;kk++)
if(notcan[p][kk]) no[p]=1;
}
cost[i][j]=dij();
}
}
std::memset(f,0x3f,sizeof f);f[0]=-k;
for(reg int i=1;i<=t;i++){
for(reg int j=0;j<i;j++) f[i]=std::min(f[i],f[j]+cost[j+1][i]*(i-j)+k);
}
std::printf("%lld",f[t]);
}