物流运输
1003: [ZJOI2006]物流运输
给出m(<=20)个点,e条边,从1走到m一共n(<=100)天,但是某一些点会在a~b这段时间里面关闭,所以就要更换落线,每一次更换路线都要消耗权值k,问在n天里从1到m的最小花费。
首先数据范围是很小的,就可以维护在某一段时间里的最短路。
那么再定义状态dp[i]表示前前i天所花费的权值。转移方程不难写出f[i] = min(dijkstra(1,i),f[j]+dijkstra(j+1,n)+k).
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 110;
const int E = 20010;
const int inf = 1<<30;
int n,m,k,e,d;
int f[N],dis[N];
bool done[N],flag[N][N];
struct edge{
int v,w;
edge *nxt;
}*head[N],*cur,meo[E];
struct node{
int dis,u;
bool operator < (const node &rhs)const{
return dis>rhs.dis;
}
};
void addedge(int u,int v,int w){
cur->v = v;
cur->w = w;
cur->nxt = head[u];
head[u] = cur++;
cur->v = u;
cur->w = w;
cur->nxt = head[v];
head[v] = cur++;
}
int dijkstra(int s,int t){
priority_queue <node> q;
memset(done,false,sizeof(done));
for(int i = 1;i <= m;++i)
for(int j = s;j <= t;++j){
if(flag[i][j]){
done[i] = true;
break;
}
}
for(int i = 1;i <= m;++i)dis[i] = inf;
dis[1] = 0;
q.push((node){dis[1],1});
while(!q.empty()){
node p = q.top();q.pop();
int u = p.u;
if(done[u])continue;
done[u] = true;
for(edge *it = head[u];it;it = it->nxt){
int v = it->v;
if(done[v])continue;
if(dis[v] > dis[u]+it->w){
dis[v] = dis[u]+it->w;
q.push((node){dis[v],v});
}
}
}
return (dis[m] == inf) ? dis[m] : dis[m]*(t-s+1);
}
int main(){
cur = meo;
ios::sync_with_stdio(false);
cin>>n>>m>>k>>e;
for(int i = 1;i <= e;++i){
int u,v,w;
cin>>u>>v>>w;
addedge(u,v,w);
}
cin>>d;
for(int i = 1;i <= d;++i){
int p,a,b;
cin>>p>>a>>b;
for(int j = a;j <= b;++j)flag[p][j] = true;
}
for(int i = 1;i <= n;++i){
f[i] = dijkstra(1,i);
for(int j = 1;j < i;++j){
f[i] = min(f[i],f[j]+dijkstra(j+1,i)+k);
}
}
cout<<f[n]<<endl;
return 0;
}