【洛谷】 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; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮