物流运输题解

物流运输题解

题目大意

从A到B有些路径,每次过边需要成本,且某些天某个点不能被经过,求n天之内,A到B不间断的最小成本。

基本思路

最短路+dp

首先求每天最小成本肯定是要最短路的(dijkstra/spfa,数据不大的floyd也应该可以)
然而换路这个东西是需要成本的,所以需要dp?[本来是想暴力的,然而会gg]

如何dp

首先可知 在第i天时,有变换路径与不变换路径两种选择

如果原来的路径此时不能走了就只好变换路径,就需要k的成本

然而 若在第i天最短路为路径 α \alpha α,第i+1天最短路径变为 β \beta β,第i+2天最短路径变成了 γ \gamma γ,逐天换路的话就需要2*k的成本,但若直接从 α \alpha α换成 γ \gamma γ的话就只需要k的花费

我们可以考虑这样做,求出从第i天到第j天都可以走的最短路成本乘上(j-i+1),加上第i-1天及以前的总成本,再加上换路径的花费k

O ( n 2 ∗ m ) O(n^{2}*m) O(n2m) 复杂度能过 ?

代码实现

本人懒 不想写链表 23333333

#include <bits/stdc++.h> 
using namespace std;
int n,m,k,e;
int mp[21][21];
int d;
int a[21][110];
int dp[110];
int now[21];
int spfa(){
    queue<int> q;
    int dis[21];
    int vis[21];
    memset(dis,0x7f7f7f7f,sizeof dis);
    memset(vis,false,sizeof vis);
    dis[1]=0;
    q.push(1);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=1;i<=m;i++){
            if(now[i]) continue;
            if(mp[u][i]>0&&dis[i]>dis[u]+mp[u][i]){
                dis[i]=dis[u]+mp[u][i];
                if(vis[i]==0){
                    q.push(i);
                    vis[i]=1;
                }
            }
        }
    }
    return dis[m];
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(false);   //关同步优化系列 然而noip不能关
    cin>>n>>m>>k>>e;
    for(register int i=1;i<=m;i++){   //register 寄存器优化(虽然优化效果甚微)
        for(register int j=1;j<=m;j++){  //然而noip暴力优化还有很有用的
            mp[i][j]=0x7f7f7f7f;          //noip评测机为core i7
        }                                   //每秒计算次数大于1e8(远大于洛~谷等网站的1e7)
    }                                       //暴力友的福利  233333333
    for(register int i=1;i<=e;i++){
        int f,t,l;
        cin>>f>>t>>l;
        mp[f][t]=l;
        mp[t][f]=l;
    }
    cin>>d;
    for(register int i=1;i<=d;i++){
        int aa,b,p;
        cin>>p>>aa>>b;
        for(register int j=aa;j<=b;j++){
            a[p][j]=1;
        }
    }
    memset(dp,0x7f7f7f7f,sizeof dp);
    dp[0]=-k;
    for(register int i=1;i<=n;i++){
        memset(now,0,sizeof now);
        for(register int l=1;l<=m;l++)now[l]=0;
        for(register int j=i;j>=1;j--){
            for(int l=1;l<=m;l++)now[l]|=a[l][j];
            int ll=spfa();
            if(ll==0x7f7f7f7f)continue;
            dp[i]=min(dp[i],dp[j-1]+ll*(i-j+1)+k);
        }
    }
    cout<<dp[n];
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值