zoukankan      html  css  js  c++  java
  • 物流运输(最短路+dp)

    这道题是相当的,但是在tyher的讲解下我一遍就AC了!!!

    Part 1 理解题目

    从第一天到最后一天,总会有一些点莫名其妙地走不了,所以导致我们不能按照上一次的最短路一直运输得到最少费用,而需要不停地更换航线来保证可以运到终点,答案就是在这些方案中选出运输费用最少的。

    Part 2 思想过程

    首先会想到我们每天都跑一遍SPFA,找最短路,如果和上一天不一样,那就改航线,加一下K的贪心方法。这样显然是错误的伪得不能再伪的贪心,而且要把最短路一个一个抠出来,不说T,写都写死你!

    然后我们发现,这道题每天无非就两种决策,一种换航线,一种不换航线。那么,就可以想到dp(至于怎么想到的……题解帮我想的)我们设dp[i]表示前i天航行送完所有的货物所需要的最小花费。转移:dp[i]=min(dp[i],dp[j]+K+w[j+1][i]);这里的j是枚举的i之前的第几天,w[i][j]是从i天到j天航线都可以走的最短路,K是换航线的费用。既然出现了“最短路”这种东西,那就SPFA吧,把这期间不能走的点标记一下,跑一遍裸的SPFA,再记入数组,算一个王者预处理吧……哈哈哈……

    Part 3 代码实现

    dp过程

    1 for(rg int i=1;i<=day;++i)
    2 {
    3     dp[i]=w[1][i];
    4     for(rg int j=1;j<i;++j)
    5     {
    6         p[i]=min(dp[i],dp[j]+K+w[j+1][i]);
    7     }
    8 }

    SPFA之前的处理码头

      读入损坏码头

    1 for(rg int i=1;i<=d;++i)
    2 {
    3     rg int p=read(),a=read(),b=read();
    4     for(rg int j=a;j<=b;++j)
    5       bre[j][++bre[j][0]]=p;
    6 }

      标记损坏码头(每一次枚举到的时间区间都要做)

    memset(b,0,sizeof(b));
    for(rg int k=i;k<=j;++k)
    {
        for(rg int l=1;l<=bre[k][0];l++)
        {
            b[bre[k][l]]=1;
        }
    }

    SPFA模板

    inline void SPFA()
    {
        memset(vis,0,sizeof(vis));
        memset(team,0,sizeof(team));
        for(rg int i=1;i<=n;++i)dis[i]=9999999;
        rg int top=0,tail=1;
        team[1]=1;vis[1]=1;dis[1]=0;
        while(top<tail)
        {
            top++;
            rg int now=team[top];vis[now]=0;
            for(rg int i=head[now];i;i=ljl[i].nxt)
            {
                rg int qw=ljl[i].to;
                if(dis[qw]>dis[now]+ljl[i].v&&!b[qw])
                {
                    dis[qw]=dis[now]+ljl[i].v;
                    if(!vis[qw])
                    {
                        team[++tail]=qw;
                        vis[qw]=1;
                    }
                }
            }
        }
    }

    完整代码!!!

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<iomanip>
    #include<algorithm>
    #include<ctime>
    #include<queue>
    #define rg register
    #define lst long long
    #define N 150
    #define M 1200
    using namespace std;
    
    int day,n,K,m,d,cnt;
    struct edge{
        int to,v,nxt;
    }ljl[M<<1];
    int head[N],team[N],dis[N],dp[N];
    int w[N][N],bre[N][N];
    bool vis[N],b[N];
    
    inline int read()
    {
        rg int s=0,m=1;rg char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')m=-1,ch=getchar();
        while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
        return s*m;
    }
    
    inline void add(rg int p,rg int q,rg int o)
    {
        ljl[++cnt].to=q;
        ljl[cnt].v=o;
        ljl[cnt].nxt=head[p];
        head[p]=cnt;
    }
    
    inline void SPFA()
    {
        memset(vis,0,sizeof(vis));
        memset(team,0,sizeof(team));
        for(rg int i=1;i<=n;++i)dis[i]=9999999;
        rg int top=0,tail=1;
        team[1]=1;vis[1]=1;dis[1]=0;
        while(top<tail)
        {
            top++;
            rg int now=team[top];vis[now]=0;
            for(rg int i=head[now];i;i=ljl[i].nxt)
            {
                rg int qw=ljl[i].to;
                if(dis[qw]>dis[now]+ljl[i].v&&!b[qw])
                {
                    dis[qw]=dis[now]+ljl[i].v;
                    if(!vis[qw])
                    {
                        team[++tail]=qw;
                        vis[qw]=1;
                    }
                }
            }
        }
    }
    
    int main()
    {
        day=read(),n=read(),K=read(),m=read();
        for(rg int i=1;i<=m;++i)
        {
            rg int p=read(),q=read(),o=read();
            add(p,q,o),add(q,p,o);
        }
        d=read();
        for(rg int i=1;i<=d;++i)
        {
            rg int p=read(),a=read(),b=read();
            for(rg int j=a;j<=b;++j)
                bre[j][++bre[j][0]]=p;
        }
        for(rg int i=1;i<=day;++i)
        {
            for(rg int j=i;j<=day;++j)
            {
                memset(b,0,sizeof(b));
                for(rg int k=i;k<=j;++k)
                {
                    for(rg int l=1;l<=bre[k][0];l++)
                    {
                        b[bre[k][l]]=1;
                    }
                }
                SPFA();
                if(dis[n]!=9999999)w[i][j]=(j-i+1)*dis[n];
                else w[i][j]=dis[n];
            }
        }
        for(rg int i=1;i<=day;++i)
        {
            dp[i]=w[1][i];
            for(rg int j=1;j<i;++j)
            {
                dp[i]=min(dp[i],dp[j]+K+w[j+1][i]);
            }
        }
        cout<<dp[day]<<endl;
        return 0;
    }




    哪怕人间是炼狱,梦想永远是天堂
    继续走下去吧,理想永远都年轻,花儿一定会再次盛开
  • 相关阅读:
    5.11实例应用
    VS2015调试
    4.4空间平滑
    4.3图像噪声
    4.2 傅里叶变换
    4.1 图像采样
    4.5.实例应用
    关于split和merge出错问题解决
    Ansible用于网络设备管理 part 3 使用NAPALM成品库
    记办公室小机房停电
  • 原文地址:https://www.cnblogs.com/cjoierljl/p/8463440.html
Copyright © 2011-2022 走看看