suxxsfe

一言(ヒトコト)

bzoj 1003 [ZJOI2006]物流运输

Description

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

Input

第一行是四个整数\(n(1\leq n\leq 100),m(1\leq m\leq 20),K,e\)\(n\)表示货物运输所需天数,\(m\)表示码头总数,\(K\)表示每次修改运输路线所需成本。
接下来\(e\)行每行是一条航线描述,包括了三个整数,依次表示航线连接的两个码头编号以及航线长度\((>0)\)。其中码头\(A\)编号为\(1\),码头\(B\)编号为4m$。单位长度的运输费用为\(1\)。航线是双向的。
再接下来一行是一个整数\(d\),后面的\(d\)行每行是三个整数\(P( 1 < P < m),a,b(1\leq 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\)天,每一天的最短路都会小于等于\(\text{cost}(i,j)\)
\(\text{cost}(i,j)\cdot (j-i+1)\)也就是\(i\)\(j\)天一直不改变路线,所需要的最小花费,这一点下面要用到
求法就直接按定义来就行,用一个\(no\)数组标记每个码头是不是不能用

然后就应该用dp来处理了,设\(f(i)\)为前\(i\)天的最小费用和,包括改变路线的费用
那如何转移?
枚举要在哪一天改变路线,记这个天数减\(1\)\(j\),那么\(f(i)=\min(f(j)+\text{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)+\text{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]);
}
posted @ 2020-03-23 19:24  suxxsfe  阅读(131)  评论(0编辑  收藏  举报