【NOIP模擬】貨物運輸

題目描述

南沙羣島有N個島嶼上駐紮有邊防部隊。每個島嶼的位置用一個平面座標(Xi,Yi)來表示,島嶼間的行程費用被認爲是兩者間的距離。例如,兩個點(X1,Y1),(X2,Y2),它們的直線距離爲:

 。

軍隊基地在座標爲(0,0)的島嶼裏面,基地存放了常用的生活物資。基地準備給每個島嶼分別送去 Qi(1≤Qi≤1000)單位的貨物。唯一負責運輸的一艘貨輪由基地取出貨物,按照島嶼編號的先後順序運送到每個島嶼(卸貨時間忽略不計),然後返回基地。也就是說貨物送到第 i-1 個島嶼後,下一個要送去貨物的就應該是第 i 個島嶼。可是由於貨輪的運載量有限,一次航行最多隻能運載C(Q≤C≤10000)單位的貨物,所以有可能需要來回基地多次才能將全部貨物送完。注意:處於島嶼安全性考慮,貨輪可以經過每個島嶼多次,但只能在每個島嶼上一次卸載完貨物。最後貨輪要回到基地。

請你設計一個運輸方案,使得總行程費用最小。

輸入格式

第一行爲 2 個正整數 N 和 C ,表示島嶼數(不含基地)和貨輪的最大運載量。
接下來 N 行,每行三個整數 Xi,Yi 和 Qi,表示按照島嶼的先後順序,第 i 個島嶼的 X 軸和 Y 軸座標及其預訂貨物量。0≤Xi , Yi≤10000 ,每個島嶼(包括基地)的座標都不同。

輸出格式

輸出一個實數,表示送完所有貨物的最小總行程費用,四捨五入保留 2 位小數。

樣例數據 1

輸入  [複製]

3 4
0 3 2
4 0 2
5 0 2

輸出

16.00

備註

【樣例說明】

從(0,0)出發,裝 2 個單位貨物到第 1 個島嶼(0,3),然後返回基地;
從(0,0)出發,裝 4 個單位貨物到第 2 個島嶼(4,0),卸下 2 個單位的貨物,接着從第 2 個島嶼到第 3 個島嶼(5,0)並卸下 2 個單位貨物;最後從第 3 個島嶼沿直線返回基地。

【數據規模】
對於 30% 的數據:2≤N≤100;
對於 60% 的數據:2≤N≤1000;
對於 100% 的數據:2≤N≤50000;

 

解析:

       DP再不練就真的廢了。。。

       狀態:f[i]表示供給完前i個島嶼並回到大本營最小的成本。

       狀態轉移方程:f[i]=min(f[j]+dis[j+1]+dis[i]+sum[i]-sum[j+1])

       初始值:f[0]=0

       dis[i]:第i個島嶼距離大本營的距離。

       sum[i]:前i個島嶼兩兩之間的距離之和。

       狀態轉移方程具體的意義就是枚舉最後一次進行供給第一個到達的島嶼,我們發現f[j]+dis[j+1]-sum[j+1]是變量且要求最小,其餘均爲常量,用單調隊列維護f[j]+dis[j+1]-sum[j+1]的最小值即可。

       PS:用deque寫單調隊列非常方便。

 

代碼:
 

#include <bits/stdc++.h>
using namespace std;

const int Max=50010;
int n,m,head=1,tail=1;
struct shu{int id,s;}p[Max];
double x[Max],y[Max],sum[Max],dis[Max],num[Max],f[Max];
deque<int>q;

inline int get_int()
{
	int x=0,f=1;
	char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-') f=-1,c=getchar();
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}

inline double calc(int i,int j)
{
	return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
inline double get(int x)
{
	return f[x]+dis[x+1]-sum[x+1];
}
inline void pop(int x)
{
	while(q.size()&&num[x]-num[q.front()]>m) q.pop_front();
}
inline void push(int x)
{
	while(q.size()&&get(x)<get(q.back())) q.pop_back();
	q.push_back(x);
}
inline void NEW(int x)
{
	f[x]=get(q.front())+dis[x]+sum[x];
}

int main()
{
	n=get_int(),m=get_int();
	for(int i=1;i<=n;i++)
	{
	  x[i]=get_int(),y[i]=get_int(),num[i]=get_int()+num[i-1],dis[i]=calc(0,i);
	  if(i!=1) sum[i]=calc(i,i-1)+sum[i-1];
	}
	push(0);
	for(int i=1;i<=n;i++) pop(i),NEW(i),push(i);
	printf("%.2f",f[n]);
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章