[BZOJ 1003][ZJOI2006]物流運輸trans

來源:互聯網
上載者:User

標籤:dp   spfa   圖論   最短路   

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 Input5 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 OutputSample Output
32
HINT

前三天走1-4-5,後兩天走1-3-5,這樣總成本為(2+2)*3+(3+2)*2+10=32

Source

 

很明顯用最短路,只不過換了種形式而已,按時間DP,在決策時跑最短路,每段時間內不能用的點就在SPFA過程中禁掉(擴充隊列中的點時加條件判斷即可),決策時求出一段時間的最短路並更新DP數組即可,雖然思路看上去很簡單,不過我還是被卡了2天才做出來(大牛中的水題在蒟蒻眼裡看來也很難AC啊),看來我基礎不是很牢,還得紮實基礎才能提高實力

<p>//DP+SPFA最短路#include <stdio.h>#include <string.h>#include <stdlib.h>#include <algorithm></p><p>#define MAXN 250#define MAXM 100000</p><p>using namespace std;</p><p>int f[MAXM],n,m,k,e,d,cnt=0; //f[i]=到第i天的最少花費,f[i]=min{f[j]+cost[j+1][i]*(i-j)+k},cnt=邊的總數struct Line{ int from,to,w; //起點,終點,邊權 int next;}edges[MAXM]; //邊集int start[MAXM],end[MAXM],head[MAXM]; //start[i]=第i個點的佔用起始時間,end[i]=第i個點的佔用結束時間int dis[MAXM]; //dis[i]=從起點到第i個點的距離,SPFA用int q[MAXM]; //類比隊列,SPFA用int visit[MAXM]; //visit[i]表示點i被訪問過int minDis[MAXN][MAXN]; //minDis[i][j]=第i-j天的最短路 int day[MAXM],pt[MAXM];void addLine(int U,int V,int W) //加入u->v,邊權為w的{有}向邊{ edges[cnt].from=U; edges[cnt].to=V; edges[cnt].w=W; edges[cnt].next=head[U]; head[U]=cnt++;}void init() //輸入資料{ int i,j,l,U,V,W,p,a,b; memset(head,-1,sizeof(head)); scanf("%d%d%d%d",&n,&m,&k,&e); for(i=1;i<=e;i++) {  scanf("%d%d%d",&U,&V,&W); //輸入邊  addLine(U,V,W); //加邊  addLine(V,U,W); } scanf("%d",&d); for(i=1;i<=d;i++)  scanf("%d%d%d",&pt[i],&start[i],&end[i]);}void preWork(int day1,int day2){ int i,j; memset(day,1,sizeof(day)); for(i=1;i<=d;i++) {  if(start[i]>day2||end[i]<day1) continue;  day[pt[i]]=0; }}int SPFA() //SPFA求day1~day2始終暢通的最短路{ int i,j,k,h=1,t=2,now; //h=隊首,t=隊尾,now=隊首的點 memset(dis,0x3f,sizeof(dis)); //初始時所有點和起點最短距離均為+∞ //memset(visit,0,sizeof(visit)); //清空隊列中的點的標記 dis[1]=0; //起點到起點距離為0 q[1]=1; //隊列中先將起點入隊 visit[1]=1; //標記起點訪問過 while(h<t) {  now=q[h];  h++; //獲得隊首後將隊首出隊  visit[now]=0;  for(i=head[now];i!=-1;i=edges[i].next)  {   if(day[edges[i].to]&&(dis[edges[i].to]==0||dis[now]+edges[i].w<dis[edges[i].to])) //如果第i個點在[day1,day2]是暢通的,從now到i的新路比舊路更近,擴充它   {    dis[edges[i].to]=dis[now]+edges[i].w; //更新更優解    if(!visit[edges[i].to])    {     q[t++]=edges[i].to; //點i入隊     visit[edges[i].to]=1;    }   }  } } return dis[m]; //返回起點1到終點m的距離}void solve() //DP求解{ int i,j,l,t; for(i=1;i<=n;i++)   for(j=1;j<=n;j++)   {    preWork(i,j);    minDis[i][j]=SPFA();   } memset(f,0x3f,sizeof(f)); //將動規數組全部置為無窮大 f[0]=0; //dp初始化 for(i=1;i<=n;i++)  for(j=1;j<=i;j++)  {   if(minDis[j][i]>=0x3f3f3f3f||f[j-1]>=0x3f3f3f3f) continue;   f[i]=min(f[i],f[j-1]+minDis[j][i]*(i-j+1)+k); //更新更優解  } printf("%d\n",f[n]-k); //輸出時要注意減去一個k(第一次運東西時減了k,實際不用減,因為第一次沒有變更航線)}int main(){ init(); solve();  return 0;}</p>


 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.