BZOJ1003 [ZJOI2006]物流运输 最短路+DP

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 10117  Solved: 4455
[Submit][Status][Discuss]

Description

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

Input

  第一行是四个整数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的运输路线。

Output

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

Sample Input

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

Sample Output

32
//前三天走1-4-5,后两天走1-3-5,这样总成本为(2+2)*3+(3+2)*2+10=32
 
题解:
用block[p][day]记录第day天码头p的开放情况。
用cost[l][r]维护第l天到第r天走同一路线所需的花费,跑n^2遍dijkstra求cost,每次n×m扫一遍所有码头的开放情况。
最后用dp求前i天的花费:dp[i] = min(dp[i],dp[j] + k + cost[j+1][i])  其中(0<=j<i);
mdzz一开始edge数组开了2×m调试了半天
dijkstra:
/**************************************************************
    Problem: 1003
    User: mizersy
    Language: C++
    Result: Accepted
    Time:72 ms
    Memory:1396 kb
****************************************************************/
 
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 25;
const int N = 105;
int n,m,k,e,p,P,l,r;
int head[maxn];
struct Edge{
    int to,next,w;
}edge[maxn*maxn*2];
int dis[maxn],vis[maxn];
ll cost[N][N],dp[N];
bool block[maxn][N];
struct Node{
    int u,w;
    bool operator < (const Node &a) const {
        return w > a.w;
    }
};
  
  
void init(){
    memset(head,-1,sizeof(head));
    memset(block,0,sizeof(block));
}
  
void addedge(int u,int v,int w,int e_num){
    edge[e_num] = Edge{v,head[u],w};
    head[u] = e_num;
}
  
int dijkstra(int l,int r){
    priority_queue <Node> q;
    q.push(Node{1,0});
    memset(dis,INF,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[1] = 0;
    bool judge[maxn];
    memset(judge,0,sizeof(judge));
    for (int i = 1;i <= m;++i){
        for (int k = l;k <= r;++k){
            if (block[i][k]) judge[i] = 1;
        }
    }
  
    while(!q.empty()){
        int u = q.top().u;
        q.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        for (int i = head[u];i != -1;i = edge[i].next){
            int v = edge[i].to,w = edge[i].w;
            if (judge[v]) continue;
            if (!vis[v] && dis[v] > dis[u] + w){
                dis[v] = dis[u] + w;
                q.push(Node{v,dis[v]});
            }
        }
    }
    return dis[m];
}
  
int main(){
    scanf("%d%d%d%d",&n,&m,&k,&e);
    init();
    for (int i = 1;i <= e;++i){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        addedge(u,v,w,2*i-1);
        addedge(v,u,w,2*i);
    }
    scanf("%d",&P);
    for (int i = 0;i < P;++i){
        scanf("%d%d%d",&p,&l,&r);
        for (int day = l;day <= r;++day)
            block[p][day] = 1;
    }
  
    for (int l = 1;l <= n;++l){
        for (int r = l;r <= n;++r){
            cost[l][r] = 1ll * (r - l+1) * dijkstra(l,r);
        }
    }
    for (int i = 1;i <= n;++i){
        dp[i] = cost[1][i];
        for (int j = i-1;j >= 0;--j){
            dp[i] = min(dp[i],dp[j] + k + cost[j+1][i]);
        }
    }
    printf("%lld\n",dp[n]);
}

 

 
posted @ 2018-10-07 15:11  mizersy  阅读(176)  评论(0编辑  收藏  举报