BZOJ1003 ZJOI2006 物流运输trans 最短路+一般DP
题意:一批货物从码头A运到码头B,需要n天才能运完,有的时候某个码头会无法装卸货物。这时候就必须修改运输路线,让货物能够按时到达目的地。修改路线会带来额外的成本。物流公司希望能够订一个n天的运输计划,使得总成本尽可能地小。
题解:
首先定义cost[i][j]=从第i天到第j天都可以使用的港口所组成的最短路的费用和,初始化出来就好,如果不存在赋值为INF。
定义f[i]为第i天可以使用的最少花费,那么f[i]=min(f[i],f[j-1]+cose[j][i]*(i-j+1)+K),也就是第i天由第j天都使用cost[i][j]这条路径。初始值f[1]=cost[1][1],f[0]=0。
转移的时候注意两点:①、如果cost[i][j]==INF的话不转移(不存在这样的路径)②、如果j==1的话,那么就是从第1天到第i天都在使用同一条路径,这样就不用加K
#include <queue> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int MAXN=100+2; const int MAXM=20+2; struct NODE{ int w,v; NODE *next; NODE(){} NODE(int _w,int _v,NODE *_next):w(_w),v(_v),next(_next){}; }*table[MAXM],mem[2*MAXM*MAXM]; int n,m,K,e,d,cost[MAXN][MAXN],cnt,dist[MAXM],f[MAXN]; bool can[MAXN][MAXM]; queue<int> q; void Insert(int a,int b,int c){ for(NODE *p=table[a];p;p=p->next){<pre name="code" class="cpp">//我也不确定有没用- -,因为可能存在重边,所以取最小边权 if(p->v==b){ p->w=min(p->w,c); return; } table[a]=&(mem[cnt++]=NODE(c,b,table[a])); } bool check(int a,int b,int c){//检查c在第a天到第b天能否使用 for(int i=a;i<=b;i++) if(can[i][c]) return 0; return 1; } void SPFA(int a,int b){ memset(dist,0X7F,sizeof(dist)); q.push(1),dist[1]=0; int now; while(!q.empty()){ now=q.front(),q.pop(); for(NODE *p=table[now];p;p=p->next) if(check(a,b,p->v) && dist[p->v]>dist[now]+p->w) dist[p->v]=dist[now]+p->w,q.push(p->v); } cost[a][b]=dist[m]; } int main(){ cin >> n >> m >> K >> e; for(int i=1,a,b,c;i<=e;i++){ cin >> a >> b >> c; Insert(a,b,c);Insert(b,a,c); } cin >> d; for(int i=1,P,a,b;i<=d;i++){ cin >> P >> a >> b; for(int j=a;j<=b;j++) can[j][P]=1; } for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) SPFA(i,j); memset(f,0X7F,sizeof(f)); f[1]=cost[1][1],f[0]=0; for(int i=2;i<=n;i++) for(int j=1;j<=i;j++) if(cost[j][i]<2139062143)//注意cost的取值 if(j==1) f[i]=min(f[j-1]+cost[j][i]*(i-j+1),f[i]);//注意边界情况 else f[i]=min(f[j-1]+cost[j][i]*(i-j+1)+K,f[i]); cout << f[n] << endl; return 0; }