snoi省选模拟赛 day3t1 路径规划

        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片西瓜地都浇好水,最短需要多少时间?

 

       考场上推了一个要手写16个转移的dp方程直接心态爆炸打了暴力。

       首先这个题目套了一个美丽的套子,让我们无从设计无后效性的状态,所以我们可以拨开这个外壳,便可以发现,其实总距离之和这条路被经过的次数有关。所以我们可以用cost[i][j]先来表示排序之后第i和j个位置放了传送门,经过i,j之间路径的最小代价。

       那么第一种就是整条路经都在i,j内包含,则为从i直接到j与从i到l,再从r到j的最小值。第二种就是路径左端点在i.j内,右端点在之外,那么就是从左端点到j,或者到从左端点到i的最小值了,第三种是右端点在i到j内,左端点在l左侧,那么与第二种同理。

       预处理了这样的数组,那么我们就很容易dp了,用dp[i][j]表示考虑到第i个点且第i个点用了,用了j个任意门的最小距离了,转移就是枚举前一个,加上走到的cost即可。

       下附AC代码。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define maxn 60
using namespace std;
typedef long long ll;
ll n,k;
ll dp[maxn][maxn];
ll x[maxn],b[maxn];
ll cost[maxn][maxn];
int main()
{
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++)
	{
		scanf("%lld",&x[i]);
		b[i]=x[i];
	}
	scanf("%lld",&k);
	b[n+1]=-12345678900000ll;b[n+2]=12345678900000ll;
	sort(b+1,b+1+n+2);
	for(ll i=1;i<=n+2;i++)
	{
		for(ll j=i+1;j<=n+2;j++)
		{
			for(ll mid=2;mid<=n;mid++)
			{
				ll l=min(x[mid],x[mid-1]),r=max(x[mid],x[mid-1]);
				if(b[i]<=l && l<=b[j] && b[i]<=r && r<=b[j])
					cost[i][j]+=min(r-l,l-b[i]+b[j]-r);
				else if(b[i]<=l && l<=b[j])
					cost[i][j]+=min(b[j]-l,l-b[i]);
				else if(b[i]<=r && r<=b[j])
					cost[i][j]+=min(b[j]-r,r-b[i]);
			}
		}
	}	
	memset(dp,0x3f,sizeof(dp));
	dp[1][0]=0;
	ll ans=123456764589ll;
	for(ll i=2;i<=n+1;i++)
	{
		for(ll j=1;j<=k;j++)
		{
			for(ll pre=i-1;pre>=1;pre--)
			{
				dp[i][j]=min(dp[i][j],dp[pre][j-1]+cost[pre][i]);
			}
			if(i==n+1)
			ans=min(ans,dp[i][j]);
		}	
	}
	printf("%lld\n",ans);
}


       

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值