物流运输
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; }