BZOJ-1003-物流运输trans-ZJOI2006-SPFA+DP

描述

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


分析

  • dp
  • f[i] : 前i天最小成本
  • f[i] = f[j] + k + cost[i+1][j] // cost[a][b] 表示第 a 天到第 b 天用同一条线路的成本.
  • 用 spfa 预处理出 cost, 暴力的做法即可.

代码

#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
        
        
#include 
        
        
          using namespace std; const int maxn = 20 + 5; const int maxm = 100 + 10; const int INF = 0x3f3f3f3f; struct Edge { int from, to, dist; }; struct SPFA { int n, m, s, t; int d[maxn]; bool ban[maxn], inq[maxn]; vector 
         
           edges; vector 
          
            G[maxn]; void init(int n, int s, int t) { this->n = n; this->s = s; this->t = t; } void AddEdge(int from, int to, int dist) { edges.push_back((Edge){from, to, dist}); edges.push_back((Edge){to, from, dist}); m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } int spfa(int x, int y) { queue 
           
             Q; memset(d, 0x3f, sizeof(d)); Q.push(s); inq[s] = 1; d[s] = 0; while(!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = 0; for(int i = 0; i < G[u].size(); i++) { Edge& e = edges[G[u][i]]; if(!ban[e.to] && d[e.to] > d[u] + e.dist) { d[e.to] = d[u] + e.dist; if(!inq[e.to]) Q.push(e.to), inq[e.to] = 1; } } } return d[t]; } }g; bool ban[maxn][maxm]; int dis[maxm][maxm], f[maxm]; int main() { int n, m, k, e, d; scanf("%d %d %d %d", &m, &n, &k, &e); g.init(n, 1, n); for(int i = 0; i < e; i++) { int from, to, dist; scanf("%d %d %d", &from, &to, &dist); g.AddEdge(from, to, dist); } scanf("%d", &d); for(int i = 0; i < d; i++) { int a, x, y; scanf("%d %d %d", &a, &x, &y); for(int j = x; j <= y; j++) ban[a][j] = 1; } for(int x = 1; x <= m; x++) for(int y = x; y <= m; y++) { memset(g.ban, 0, sizeof(g.ban)); for(int i = 1; i <= n; i++) for(int j = x; j <= y; j++) if(ban[i][j]) { g.ban[i] = 1; break; } dis[x][y] = g.spfa(x, y); } memset(f, 0x3f, sizeof(f)); f[0] = 0; for(int i = 1; i <= m; i++) for(int j = 0; j < i; j++) if(dis[j+1][i] != INF) f[i] = min(f[i], f[j] + k + dis[j+1][i]*(i-j)); printf("%d\n", f[m]-k); return 0; } 
            
           
          
        
       
       
      
      
     
     
    
    

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值