snoi多校模擬賽 1.17 t1 path

A 路徑規劃(path.pas/c/cpp)

TL:1S  ML:128MB

【Description】

kAc在數軸上有N片西瓜地。第 i片的座標是X[i](注意 X並沒有排序)。任意兩片西瓜地座標不同。有一天他要給這N片西瓜地澆水。初始他在X[1]的位置。他必須按1..N 的順序澆水,也就是說,必須先去X[1],再去X[2]...最後到X[n](他可以沿着座標軸正方向或者負方向走)。

給西瓜地澆水不需要花費時間。每走1單位的距離需要花費1 的時間。 現在kAc爲了節約時間  打算建立K個超時空傳送站。如果兩個位置P、Q,在這兩處位置都有超時空傳送站,那麼我們可以瞬間轉移過去(從 P到 Q或者從Q到 P) 。

現在他想知道  如果要給這 N片西瓜地都澆好水,最短需要多少時間?

【Input】

第一行一個整數N

接下來N行,每行一個整數X[i]

最後一行,一個整數K。

【Output】

輸出最短時間。

【Sample Input

4

0 6 8 2

2

【Sample Output

6

【Hint】

樣例解釋:

在1、7 兩個位置建立傳送站。

 

30%:N<=5 座標範圍<=100

100%:N<=50 座標範圍<=10^9 

想法:考場上一眼看出dp,列出了正確的狀態,但是因爲不知道怎樣轉移而GG,之後才知道這是一個dp套dp。。。

解法:cost[i][j]表示i和j建傳送門,其他地方都不建,所有路徑的花費;

dp[i][j]表示前i個點j個傳送門時的最小花費。

轉移:dp[i][j]=min(dp[i][j],dp[k][j-1]+cost[k][i]);

cost區間分類討論即可。

代碼:

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
ll n,K,tmp,dp[1005][1005],cost[1005][1005],inf=0x1f1f1f1f1f1f1f1fll,ans=inf,dis[55],x[55];
int main()
{
	memset(dp,inf,sizeof(dp));
	dp[0][0]=0;
	scanf("%lld",&n);
	for(int i=0;i<n;i++) scanf("%lld",&tmp),x[i]=dis[i]=tmp;
	scanf("%lld",&K);
	dis[n]=inf;
	dis[n+1]=-inf;
	sort(dis,dis+n+2);
	for(int i=0;i<=n+1;i++)
		for(int j=i+1;j<=n+1;j++)
			for(int k=0;k<n-1;k++)
			{
				ll l=min(x[k],x[k+1]),r=max(x[k],x[k+1]);
				if(l>=dis[i]&&l<=dis[j]&&r>=dis[i]&&r<=dis[j]) cost[i][j]+=min(r-l,l-dis[i]+dis[j]-r);
				else if(l>=dis[i]&&l<=dis[j]) cost[i][j]+=min(dis[j]-l,l-dis[i]);
				else if(r>=dis[i]&&r<=dis[j]) cost[i][j]+=min(dis[j]-r,r-dis[i]);
			}
	for(int i=1;i<=n+1;i++)
		for(int j=1;j<=K+1;j++)
			for(int k=i-1;k>=0;k--)
				dp[i][j]=min(dp[i][j],dp[k][j-1]+cost[k][i]);
	for(int i=0;i<=K+1;i++) ans=min(ans,dp[n+1][i]);
	printf("%lld\n",ans);
}


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