• P1772 [ZJOI2006]物流运输


    传送门

    预处理 dis [ i ] [ j ] 表示从第 i 天到第 j 天不改变路线的最短路径

    然后就可以愉快地推方程了

    设 f [ i ] 表示从第一天到第 i 天的最少花费

    那么 f [ j ] = min(f [ j ] , f [ i ] + dis[ i+1 ] [ j ] * (j-i) + K)

    预处理的用的是 Dijkstra

    注意最后改变航线的次数比我们方程里+K的次数少 1,所以最后要减 1

    (我的方程初始的航线也算改变,然而初始不算改变)

    // luogu-judger-enable-o2
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    using namespace std;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=1007,M=27;
    int fir[M],from[N],to[N],val[N],cnt;
    inline void add(int &a,int &b,int &c)
    {
        from[++cnt]=fir[a];
        fir[a]=cnt; to[cnt]=b; val[cnt]=c;
    }
    int n,m,e,d;
    int l[N],r[N],id[N];//存关闭港口的信息,从第l[i]到第r[i]天,id[i]号港口关闭
    int dis[107][107][M];
    bool p[M];//判断此时港口是否关闭
    struct node
    {
        int pos,dis;
        inline bool operator < (const node &tmp) const {
            return dis>tmp.dis;
        }
    };//Dijkstra的结构体
    priority_queue <node> q;
    void Dijk(int L,int R)//求从第L天到第R天不改变路线的最短路径
    {
        memset(p,0,sizeof(p));
        for(int i=1;i<=d;i++)
        {
            if(r[i]<L||l[i]>R) continue;
            p[id[i]]=1;//只要时间段有相交的区间就不能走
        }
        q.push((node){1,0}); dis[L][R][1]=0;//愉快地跑Dijkstra
        while(!q.empty())
        {
            node x=q.top(); q.pop();
            if(x.dis!=dis[L][R][x.pos]) continue;
            for(int i=fir[x.pos];i;i=from[i])
            {
                int &v=to[i]; if(p[v]) continue;
                if(dis[L][R][v]>dis[L][R][x.pos]+val[i])
                {
                    dis[L][R][v]=dis[L][R][x.pos]+val[i];
                    q.push((node){v,dis[L][R][v]});
                }
            }
        }
    }
    int K,f[N];
    int main()
    {
        memset(dis,127,sizeof(dis));
        memset(f,127,sizeof(f)); f[0]=0;//注意初始化
        int a,b,c;
        n=read(); m=read(); K=read(); e=read();
        for(int i=1;i<=e;i++)
        {
            a=read(),b=read(),c=read();
            add(a,b,c); add(b,a,c);
        }
        d=read();
        for(int i=1;i<=d;i++) id[i]=read(),l[i]=read(),r[i]=read();
        for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) Dijk(i,j);//预处理
        for(int i=0;i<n;i++)
            for(int j=i+1;j<=n;j++)
                if(dis[i+1][j][m]<2e9)//注意如果太大说明无路可走就不用考虑,不然后面乘的时候可能爆成负数
                    f[j]=min(f[j],f[i]+dis[i+1][j][m]*(j-i)+K);
        printf("%d",f[n]-K);//注意最后改变次数少一
        return 0;
    }
  • 相关阅读:
    谈谈图片上传及canvas压缩的流程
    前端应该懂得初级Web分析指标
    java OPENCV 连通域, Imgproc.findContours 例子,参数说明
    [学习opencv]高斯、中值、均值、双边滤波
    Opencv 图像叠加 添加水印
    帧间提取水印
    opencv mat 转灰度图
    编写一条sql命令,sql删除没有中文的表
    使用JavaCV/OpenCV抓取并存储摄像头图像
    周掌柜
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9869287.html
Copyright © 2020-2023  润新知