zoukankan      html  css  js  c++  java
  • [ZJOI2006]物流运输(最短路 + 区间dp)

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

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

     



    题解:

      先看一下题:本题让求出1~n天运输路线所花费的费用,表示一头雾水。。。题干中还给出,哪几个点在a~b区间范围内不可被使用,又一头雾。。。其实我们再回头看一下,1~n天的费用就是:

      1、1~x天的第一种路线费用  +  x+1天的第二种的路线费用  +   改变路线的费用

      2、1~x天的第一种路线费用  +  x+1天的第一种的路线费用 (其实这种就可以合并)。

      这样分出情况来看,我们好像就可以设出状态转移方程:

      dp[i][j]表示i~j天期间的最小路线费用(这就意味着后面所说的最短路均为从1~n的最短路,我们在此将每一天作为一个单位),那么:

    dp[1][n]=dp[1][x]+dp[x+1][y]+......+dp[z+1][n] + t*K

      
      这不就是区间dp吗?有一股正解的气息。。。

      我们来考虑一下初始化的问题(假设dp[i][j]):

      1、i==j时,就是跑一个有不能经过的点的最短路的长度(权值为一嘛)。

      2、i > j时,无解(既然跑最短路,返程肯定不需要)

      3、i < j时,毕竟是初始化,我们就假设它在i~j一段时间内没有转变路线,那么凡是在i~j期间有节点不能用,那么这个节点就一定不可能存在于现在的最短路中。我们将那几个点不可用的点标记后再跑一个最短路即可。(注意结果要乘上时间长度(j-i+1))

        我们为什么要将dp[i][j](i < j)初始化为没有转变路线的情况呢?其实这与我们后面的dp转移有关。后面的转移一定不会再考虑大片的具有相同路径的连续几天了,我们只会考虑在哪一天换一下路线使总花费变小。所以就需要在初始化时将这种可能成为答案的、大片的具有相同路径的连续几天的情况了。如果这i~j天不能用的港口太多,导致无解,那就让它无解吧,反正到后面合并时会更新,就不考虑这种情况了。

      有了上面的初始化( Dijkstra 与 spfa 都可以),我们就来写一下区间dp的式子(其实跟普通区间dp没两样):

    dp[i][j]=Σj-1q=imin(dp[i][j],dp[i][q]+dp[q+1][j]+k);

      got it!
    Code:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<queue>
     4 #define $ 210
     5 using namespace std; 
     6 int n,m,k,e,first[$],tot,d,dp[$][$],lu[$/5];
     7 bool judge[$][$/5],vis[$],pro[$];
     8 struct tree{    int to,next,w;    }a[$*2];
     9 inline int min(int x,int y){    return x<y?x:y;    }
    10 inline void add(int x,int y,int w){
    11     a[++tot]=(tree){    y,first[x],w    };
    12     first[x]=tot;
    13     a[++tot]=(tree){    x,first[y],w    };
    14     first[y]=tot;
    15 }
    16 inline int Dijkstra(int start,int done){
    17     priority_queue< pair<int,int> > q;
    18     memset(vis,0,sizeof(vis));
    19     memset(lu,63,sizeof(lu));
    20     memset(pro,0,sizeof(pro));
    21     for(register int i=start;i<=done;++i)
    22         for(register int j=1;j<=m;++j)  if(judge[i][j]) pro[j]=1;
    23     lu[1]=0;
    24     q.push(make_pair(0,1));
    25     while(q.size()){
    26         int x=q.top().second; q.pop();
    27         if(vis[x]) continue;
    28         vis[x]=1;
    29         for(register int i=first[x];i;i=a[i].next){
    30             int to=a[i].to,w=a[i].w;
    31             if(pro[to]) continue;
    32             if(lu[to]>lu[x]+w){
    33                 lu[to]=lu[x]+w;
    34                 q.push(make_pair(-lu[to],to));
    35             }
    36         }
    37     }
    38     return lu[m];
    39 }
    40 inline int spfa(int start,int done){
    41     queue<int> q;
    42     memset(vis,0,sizeof(vis));
    43     memset(lu,63,sizeof(lu));
    44     memset(pro,0,sizeof(pro));
    45     for(register int i=start;i<=done;++i)
    46         for(register int j=1;j<=m;++j)  if(judge[i][j]) pro[j]=1;
    47     q.push(1); lu[1]=0;
    48     vis[1]=1;
    49     while(q.size()){
    50         int x=q.front(); q.pop();
    51         vis[x]=0;
    52         for(register int i=first[x];i;i=a[i].next){
    53             int to=a[i].to,w=a[i].w;
    54             if(pro[to]) continue;
    55             if(lu[to]>lu[x]+w){
    56                  lu[to]=lu[x]+w;
    57                  if(!vis[to]) q.push(to),vis[to]=1;
    58             }
    59         }
    60     }
    61     return lu[m];
    62 }
    63 signed main(){
    64     memset(dp,63,sizeof(dp)); 
    65     scanf("%d%d%d%d",&n,&m,&k,&e);
    66     for(register int i=1,x,y,z;i<=e;++i)
    67         scanf("%d%d%d",&x,&y,&z),add(x,y,z);
    68     scanf("%d",&d);
    69     for(register int i=1,x,l,r;i<=d;++i){
    70         scanf("%d%d%d",&x,&l,&r);
    71         for(register int j=l;j<=r;++j) judge[j][x]=1;
    72     }
    73     for(register int i=1;i<=n;++i)
    74         for(register int j=i,x;j<=n;++j){ 
    75             x=i%2?Dijkstra(i,j):spfa(i,j);
    76             if(x<100000) dp[i][j]=x*(j-i+1);
    77             else         dp[i][j]=0x7ffffff;
    78         }
    79     for(register int l=2;l<=n;++l){
    80         for(register int i=1;i<=n-l+1;++i){
    81             int j=i+l-1;
    82             for(register int q=i;q<j;++q)
    83                 dp[i][j]=min(dp[i][j],dp[i][q]+dp[q+1][j]+k);
    84         }
    85     }
    86     printf("%d
    ",dp[1][n]);
    87 }
    View Code
    越努力 越幸运
  • 相关阅读:
    javascritp对fckeditor编辑器赋值取值
    [.net]发布基于C#与Flash通信的游戏设计器完整项目及源代码下载
    Sun VirtualBox更新到3.0.8.53138
    JavaScript强弹代码
    给Repeater、Datalist和Datagrid增加自动编号列
    Adobe发布新版Photoshop.com 支持iPhone
    网站免费提交搜索引擎入口地址?
    利用FMS做在线视频录制
    Apache Lucene 2.9的改进
    KDE 4.3.2 发布
  • 原文地址:https://www.cnblogs.com/OI-zzyy/p/11177941.html
Copyright © 2011-2022 走看看