题目提供者 洛谷
难度 提高+/省选-
题目描述
物流公司要把一批货物从码头 A 运到码头 B。由于货物量比较大,需要 n 天才能运完。货物运输过程中一般要转停好几个码头。
物流公司通常会设计一条固定的运输路线,以便对整个运输过程实施严格的管理和跟踪。由于各种因素的存在,有的时候某个码头会无法装卸货物。这时候就必须修改运输路线,让货物能够按时到达目的地。
但是修改路线是—件十分麻烦的事情,会带来额外的成本。因此物流公司希望能够订一个 n 天的运输计划,使得总成本尽可能地小。
输入格式
第一行是四个整数 n,m,k,e。n 表示货物运输所需天数,m 表示码头总数,k表示每次修改运输路线所需成本,e 表示航线条数。
接下来 e 行每行是一条航线描述,包括了三个整数,依次表示航线连接的两个码头编号以及航线长度。其中码头 A 编号为 1,码头 B 编号为 m。单位长度的运输费用为 1。航线是双向的。
再接下来一行是一个整数 d,后面的 d 行每行是三个整数 p,a,b。表示编号为 p的码头在 [a,b] 天之内无法装卸货物。同一个码头有可能在多个时间段内不可用。但任何时间都存在至少一条从码头 A 到码头 B 的运输路线。
输出格式
包括了一个整数表示最小的总成本。
总成本为 nn 天运输路线长度之和 +k × 改变运输路线的次数。
输入输出样例
输入 #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% 的数据,1 ≤ n ≤ 100,1 ≤ m ≤ 20,1 ≤ k ≤ 500,1 ≤ e ≤ 200。
【样例输入说明】
上图依次表示第 11 至第 55 天的情况,阴影表示不可用的码头。
【样例输出说明】
前三天走 1→4→5,后两天走 1→3→5,这样总成本为 (2+2)×3+(3+2)×2+10=32。
_NOI导刊2010提高(01)
题解:
#include<bits/stdc++.h>
#define soo (1e8)
#define ll long long
using namespace std;
int d,cnt,head[25],dis[25],vis[25],cant_vis[25];
ll co[105][105],dp[105];
int n,m,k,ee,cl[25][105];
struct Edge{
int v,nx,s;
}e[10005];
inline int read(){
int ret=0,ff=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') ff=-ff;ch=getchar();}
while(isdigit(ch)){ret=(ret<<3)+(ret<<1)+ch-'0';ch=getchar();}
return ret*ff;
}
void add(int x,int y,int z){
e[++cnt].v=y;
e[cnt].s=z;
e[cnt].nx=head[x];
head[x]=cnt;
}
void spfa(){//爱跑什么跑什么
for(int i=1;i<=m;i++) dis[i]=soo,vis[i]=0;
queue<int> q;
dis[1]=0;
q.push(1);
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=0;
for(int i=head[x];i;i=e[i].nx){
int v=e[i].v;
if(cant_vis[v]) continue;
if(dis[v]>dis[x]+e[i].s){
dis[v]=dis[x]+e[i].s;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
}
signed main(){
n=read(),m=read(),k=read(),ee=read();
for(int i=1;i<=ee;i++){
int x=read(),y=read(),z=read();
add(x,y,z);
add(y,x,z);
}
d=read();
for(int i=1;i<=d;i++){
int t=read(),x=read(),y=read();
for(int j=x;j<=y;j++) cl[t][j]=1;
}
//cl[i][j]表示第i个码头在第j天不能走
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
memset(cant_vis,0,sizeof(cant_vis));
for(int r=i;r<=j;r++)
for(int l=1;l<=m;l++)
if(cl[l][r]) cant_vis[l]=1;
spfa();
co[i][j]=dis[m];
}
memset(dp,0x7f,sizeof(dp));
for(int i=1;i<=n;i++){
dp[i]=(ll)co[1][i]*i;
for(int j=i-1;j>=0;j--)
dp[i]=min(dp[i],dp[j]+co[j+1][i]*(i-j)+k);
}
printf("%lld",dp[n]);
return 0;
}
成功图片: