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);
}


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