BZOJP1003 [ZJOI2006]物流运输trans
BZOJP1003 [ZJOI2006]物流运输trans
1003: [ZJOI2006]物流运输trans
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 4755 Solved: 1977
[Submit][Status][Discuss]
Description
物流公司要把一批货物从码头A运到码头B。由于货物量比较大,需要n天才能运完。货物运输过程中一般要转停好几个码头。物流公司通常会设计一条固定的运输路线,以便对整个运输过程实施严格的管理和跟踪。由于各种因素的存在,有的时候某个码头会无法装卸货物。这时候就必须修改运输路线,让货物能够按时到达目的地。但是修改路线是一件十分麻烦的事情,会带来额外的成本。因此物流公司希望能够订一个n天的运输计划,使得总成本尽可能地小。
Input
第一行是四个整数n(1<=n<=100)、m(1<=m<=20)、K和e。n表示货物运输所需天数,m表示码头总数,K表示每次修改运输路线所需成本。接下来e行每行是一条航线描述,包括了三个整数,依次表示航线连接的两个码头编号以及航线长度(>0)。其中码头A编号为1,码头B编号为m。单位长度的运输费用为1。航线是双向的。再接下来一行是一个整数d,后面的d行每行是三个整数P( 1 < P < m)、a、b(1 < = a < = b < = n)。表示编号为P的码头从第a天到第b天无法装卸货物(含头尾)。同一个码头有可能在多个时间段内不可用。但任何时间都存在至少一条从码头A到码头B的运输路线。
Output
包括了一个整数表示最小的总成本。总成本=n天运输路线长度之和+K*改变运输路线的次数。
Sample Input
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
Sample Output
32
HINT
前三天走1-4-5,后两天走1-3-5,这样总成本为(2+2)*3+(3+2)*2+10=32
【思路】
SPFA+DP。
设d[i]表示前i天运输的最小成本则有转移式:
d[i]=min{ d[j]+cost(j+1,i)*(i-j)+K }
其中cost(j+1,i)表示这一时间段内一直可以通行的最短路,这一决策代表了j+1到i时间内一直用这条最短路运输。
Cost可以每次用SPFA求出,需要注意的是如何判断在一时间段内一个港口是否可行。
另外注意:题目中有重边,一个港口可以多次不通行。
【代码】
1 #include<iostream> 2 #include<cstring> 3 #include<vector> 4 #include<queue> 5 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 6 using namespace std; 7 8 const int maxn = 20+10; 9 const int maxm = 100+10; 10 const int INF = 1<<30; 11 12 13 int n,m,K,e; 14 int can[maxn][2],f[maxm]; 15 int w[maxn][maxn]; 16 int A[maxn][maxm]; 17 18 void init(){ 19 memset(w,0,sizeof(w)); 20 cin>>n>>m>>K>>e; 21 int u,v,ww; 22 FOR(i,1,e) { 23 cin>>u>>v>>ww; 24 if(!w[u][v] || ww<w[u][v]) w[u][v]=w[v][u]=ww; //重边 25 } 26 /* //失败写法 一个p可以有多次不能使用 //可以化成vector 27 int d; cin>>d; 28 FOR(i,1,d) { 29 int p,a,b; cin>>p>>a>>b; 30 can[p][0]=a; can[p][1]=b; 31 } 32 */ 33 //前缀和思想判断是否可以使用 34 int d; cin>>d; 35 FOR(i,1,d) { 36 int p,a,b; cin>>p>>a>>b; 37 FOR(j,a,b) A[p][j]=1; 38 } 39 FOR(i,1,m){ 40 A[i][0]=0; 41 FOR(j,1,n) 42 A[i][j] += A[i][j-1]; 43 } 44 } 45 46 int SPFA(int s,int t) 47 //在时间st之内满足条件的最短路 48 { 49 bool inq[maxn]; int d[maxn]; 50 fill(d,d+m+1,INF); 51 memset(inq,false,sizeof(inq)); 52 queue<int> q; 53 inq[1]=1; d[1]=0; q.push(1); 54 while(!q.empty()) 55 { 56 int u=q.front(); q.pop(); inq[u]=false; 57 for(int v=1;v<=m;v++) 58 if(w[u][v]){ 59 if(A[v][t]-A[v][s-1]==0 && d[v]>d[u]+w[u][v]) { 60 d[v]=d[u]+w[u][v]; 61 if(!inq[v]) { 62 inq[v]=true; 63 q.push(v); 64 } 65 } 66 } 67 } 68 return d[m]; 69 } 70 71 void solve() { 72 memset(f,25,sizeof(f)); 73 f[0]=0; //显式把边界写出来 74 FOR(i,1,n) 75 { 76 FOR(j,0,i-1) 77 { 78 int cost=SPFA(j+1,i); 79 if(cost<INF) f[i]=min(f[i],f[j]+cost*(i-j)+K); 80 } 81 } 82 cout<<f[n]-K<<"\n"; //减去多算的一次K 83 } 84 85 int main() { 86 ios::sync_with_stdio(false); 87 88 init(); 89 solve(); 90 91 return 0; 92 }
posted on 2015-10-22 11:57 hahalidaxin 阅读(273) 评论(0) 编辑 收藏 举报