• bzoj 1003 [ZJOI2006]物流运输


    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]);
    }
    
  • 相关阅读:
    shell字符串截取
    QT,QT SDK, QT Creator 区别
    linux -- 扩容 /home 空间( xfs文件系统分区扩容指定挂载点)
    条件变量与互斥量
    越努力越幸运--2018年7月22日周记
    越努力越幸运--动态数组vector
    越努力越幸运--3-日常bug修复
    越努力越幸运--2-LD_PRELOAD, fork ,僵尸进程
    越努力越幸运--1
    makefile--回顾基础篇
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/12554263.html
Copyright © 2020-2023  润新知