返回顶部

【洛谷】 P1772 [ZJOI2006]物流运输 (最短路+dp)

  • 题意:有一张DAG,每条边都有边权,每一天都需要计算\(1\)\(m\)的最短路,但是有些点在某些天不能到达,假设某一天的路径和前一天的路径不同,需要额外的\(k\)个费用,保证任何时候\(1\)\(m\)一定连通,问你\(n\)天下来的最少总费用。

  • 题解:假设\(dp[i]\)表示前\(i\)天的最少总费用,\(cost[i][j]\)表示第\(i\)天到第\(j\)天都选同一条路径的最少费用,那么有:\(dp[i]=min(dp[i],dp[j]+cost[j+1][i]*(j-i)+k)\).可以先\(O(n^2)\)枚举天数,跑最短路求出\(cost[i][j]\),然后再dp即可.

  • 代码

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    #define pb push_back
    const int N= 1e6+10;
    const int mod=1e9+7;
    const int INF= 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
    
    int n,m,k,e;
    struct Node{
        int to;
        int w;
    }xx;
    int d;
    bool ocp[105][105];
    bool vis[N],st[N];
    ll dis[N];
    vector<Node> edge[N];
    ll cost[105][105];
    ll dp[N];
    
    void dijkstra(){
        for(int i=1;i<=m;++i) dis[i]=INF,vis[i]=false;
        dis[1]=0;
    
        priority_queue<PII,vector<PII>,greater<PII>> h;
        h.push({0,1});
    
        while(!h.empty()){
            auto tmp=h.top();
            h.pop();
    
            int num=tmp.se;
            int dist=tmp.fi;
            if(vis[num] || st[num]) continue;
            vis[num]=true;
            for(auto w:edge[num]){
                int to=w.to;
                if(dis[to]>dist+w.w){
                    dis[to]=dist+w.w;
                    h.push({dis[to],to});
                }
            }
        }
    }
    
    int main(){
        scanf("%d %d %d %d",&n,&m,&k,&e);
    
        for(int i=1;i<=e;++i){
            int a,b,w;
            scanf("%d %d %d",&a,&b,&w);
            edge[a].pb({b,w});
            edge[b].pb({a,w});
        }
    
        scanf("%d",&d);
    
        for(int i=1;i<=d;++i){
            int p,a,b;
            scanf("%d %d %d",&p,&a,&b);
            for(int j=a;j<=b;++j){
                ocp[p][j]=true;
            }
        }
    
        for(int i=1;i<=n;++i){    
            for(int j=1;j<=n;++j){
                for(int mt=1;mt<=m;++mt){
                    st[mt]=false;
                    for(int cur=i;cur<=j;++cur){
                        if(ocp[mt][cur]) st[mt]=true;
                    }
                }
                dijkstra();
                cost[i][j]=dis[m];
            }
        }
    
        for(int i=1;i<=n;++i){
            dp[i]=1ll*cost[1][i]*i;
            for(int j=1;j<i;++j){
                dp[i]=min(dp[i],dp[j]+cost[j+1][i]*(i-j)+k);
            }
        }
        
        printf("%lld\n",dp[n]);
    
        return 0;
    }
    
    
posted @ 2021-10-12 15:15  Rayotaku  阅读(38)  评论(0编辑  收藏  举报