P1772 [ZJOI2006]物流运输
题意
[ZJOI2006]物流运输
题目描述
物流公司要把一批货物从码头 A 运到码头 B。由于货物量比较大,需要 n n n 天才能运完。货物运输过程中一般要转停好几个码头。
物流公司通常会设计一条固定的运输路线,以便对整个运输过程实施严格的管理和跟踪。由于各种因素的存在,有的时候某个码头会无法装卸货物。这时候就必须修改运输路线,让货物能够按时到达目的地。
但是修改路线是—件十分麻烦的事情,会带来额外的成本。因此物流公司希望能够订一个 n n n 天的运输计划,使得总成本尽可能地小。
输入格式
第一行是四个整数 n , m , k , e n,m,k,e n,m,k,e。 n n n 表示货物运输所需天数, m m m 表示码头总数, k k k 表示每次修改运输路线所需成本, e e e 表示航线条数。
接下来 e e e 行每行是一条航线描述,包括了三个整数,依次表示航线连接的两个码头编号以及航线长度。其中码头 A 编号为 1 1 1,码头 B 编号为 m m m。单位长度的运输费用为 1 1 1。航线是双向的。
再接下来一行是一个整数 d d d,后面的 d d d 行每行是三个整数 p , a , b p,a,b p,a,b。表示编号为 p p p 的码头在 [ a , b ] [a,b] [a,b] 天之内无法装卸货物。同一个码头有可能在多个时间段内不可用。但任何时间都存在至少一条从码头 A 到码头 B 的运输路线。
输出格式
包括了一个整数表示最小的总成本。
总成本为 n n n 天运输路线长度之和 + k × +k\times +k× 改变运输路线的次数。样例 #1
样例输入 #1
5 5 10 8 1 2 1 1 3 3 1 4 2 2 3 2 2 4 4 3 4 1 3 5 2 4 5 2 4 2 2 3 3 1 1 3 3 3 4 4 5
样例输出 #1
32
提示
【数据范围】
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 100 1 \le n \le 100 1≤n≤100, 1 ≤ m ≤ 20 1\le m \le 20 1≤m≤20。【样例输入说明】
上图依次表示第 1 1 1 至第 5 5 5 天的情况,阴影表示不可用的码头。
【样例输出说明】
前三天走 1 → 4 → 5 1 \to 4 \to 5 1→4→5,后两天走 1 → 3 → 5 1 \to 3 \to 5 1→3→5,这样总成本为 ( 2 + 2 ) × 3 + ( 3 + 2 ) × 2 + 10 = 32 (2+2)\times 3+(3+2)\times 2+10=32 (2+2)×3+(3+2)×2+10=32。
_NOI导刊2010提高(01)
tags
图论:最短路径,线性dp
思路
- 距离:最短路径,最优解:dp
- 动态转移方程:
dp[i]=min(dp[i],dp[j-1]+(i-j+1)*l+k)
- dp[i]表示前i天的最短花费
- 第i天有两种选择:继续原先的路(不能走了必须的换路)、换一条路径(最短路径)
- 对于第i天,我们可以选择第i天换路径,第i-1天换路径,第i-2天换路径······第j天换路径
- 假如对于第j天换路径,那么我们最小花费是第j天到第i天走最短路径(注意此最短路径是被第j天到第i天所有不能走的所有的点限制的),所有j到哪天为止呢?不能在换路径为止:即第j-1天到第i天所有不能走的点的限制使其不能从1到m了
- 所以对于求dp[i],我们用j从j=i枚举到j=1,然后枚举过程中逐天加上不能走的点的限制,更新最短路径,直到不能换路径为止
- 注意开long long
- 注意dp[0]=-k,因为从第1天开始的话不用去换路径。
AC代码
- 最短路求法提供spfa和dijkstra两种算法
- 用noallow来存每天不能走的点,now存第j天到第i天不能走的点(逐天添加点)
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int>P;
const int maxn=105,maxm=25,maxe=1005;
int n,m,k,e,d;
int head[maxm],dis[maxm],vis[maxm];
int cnt;
ll dp[maxn];
int noallow[maxn][maxm],g[maxm];
struct Edge{
int to,cost,next;
}edge[maxe];
void addedge(int u,int v,int w){
edge[++cnt].to=v;
edge[cnt].cost=w;
edge[cnt].next=head[u];
head[u]=cnt;
}
// int spfa(){
// memset(dis,0x3f,sizeof(dis));
// memset(vis,0,sizeof(vis));
// dis[1]=0;
// vis[1]=1;
// queue<int>q;
// q.push(1);
// while(!q.empty()){
// int x=q.front();
// q.pop();
// vis[x]=0;
// for(int i=head[x];i;i=edge[i].next){
// int too=edge[i].to,costt=edge[i].cost;
// if(!g[too]&&dis[too]>dis[x]+costt){
// dis[too]=dis[x]+costt;
// if(!vis[too]){
// q.push(too);
// vis[too]=1;
// }
// }
// }
// }
// return dis[m];
// }
int dijkstra(){
priority_queue<P,vector<P>,greater<P>>q;
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[1]=0;
q.push(P(0,1));
while(!q.empty()){
int pos=q.top().second;
q.pop();
if(vis[pos])continue;
vis[pos]=1;
for(int i=head[pos];i;i=edge[i].next){
int too=edge[i].to,costt=edge[i].cost;
if(g[too])continue;
if(!vis[too]&&dis[too]>dis[pos]+costt){
dis[too]=dis[pos]+costt;
q.push(P(dis[too],too));
}
}
}
return dis[m];
}
int main(){
cin>>n>>m>>k>>e;
for(int i=0;i<e;i++){
int u,v,w;
cin>>u>>v>>w;
addedge(u,v,w);
addedge(v,u,w);
}
cin>>d;
for(int i=0;i<d;i++){
int p,a,b;
cin>>p>>a>>b;
for(int j=a;j<=b;j++)noallow[j][p]=1;
}
memset(dp,0x3f,sizeof(dp));
dp[0]=-k;
for(int i=1;i<=n;i++){
memset(g,0,sizeof(g));
for(int j=i;j>=1;j--){
for(int k=1;k<=m;k++){
if(noallow[j][k])g[k]=1;
}
int l=dijkstra();
if(l==inf)break;
dp[i]=min(dp[i],dp[j-1]+(i-j+1)*l+k);
}
}
cout<<dp[n]<<endl;
}