C. Road Optimization

题目大意:

给定3个数n,l,k,将线段将0到l通过n+1个点分成n段,每个点都有两个正整数分别d,s,d为当前点的位置到初始点的距离,s为当前点到下一个点之间这段路的速度。通过全程的总时间每个点到下一个点的距离乘上该点的速度之和。如果删除当前位置的点位,则该点的上个位置的点位到该点下个位置的点位时间为下个点位的位置减去上个点位的位置乘上上个点位的速度之和。求在删除点位个数不超过k个时通过全程最短需要的时间。

原题目的例子:

                点位        1        2        3        4        5

位置                        0        3        4        8        10

速度                        5        8        3        6        无

因为5号点位已经是终点,所以无速度。

当我们对点不做删减时,总时间为(3-0)*5+(4-3)*8+(8-4)*3+(10-8)*6=47。

当我们删除第二个点时,总时间为(4-0)*5+(8-4)*3+(10-8)*6=44

题外话:当时打CF的时候想的是用贪心,感觉局部最优就是全局最优,然后wa8=。=  。后来发现当有多个局部最优时不能随便删除,所以应该用dp来做。

题解:

开一个二维dp数组,dp[i][j]表示在第i个点时已经删除了j个点所花费的最小时间。

状态转移方程:

dp[i][k+i-j]=min(dp[i][k+i-j],dp[j-1][k]+(d[i]-d[j-1])*s[j-1])

 由于第一个点不可删除,所以j为大于等于2并且小于i的点位,dp[i][k+i-j]表示在第i个点位时删除k+i-j个点花费的时间,其值等于其原本的值和在第j-1个点位时已经删除了k个点位的时间再加上删除j到i-1之间所有的点位后花费的时间((d[i]-d[j-1])*s[j-1))的最小值。

AC代码:

#include<iostream>
#include<vector>
#include<cstring>
#include<list>
#include<cstdio>
#include<algorithm>
#include<math.h>
#include<map>
#include<queue>
#include<stack>
#include<set>
#define pb(a) push_back(a)
#define bg() begin()
#define ed() end()
#define endl "\n"
#define res(a,b) reverse(a(),b())
#define mem(a,b) memset(a,b,sizeof a)
#define ll long long
#define LLINF 2e18
#define int long long
#define flr(i,l,r) for(int i=l;i<=r;i++)
#define frl(i,r,l) for(int i=r;i>=l;i--)
inline ll lread(){register ll x=0,f=1;register char c=getchar();while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();return x*f;}
inline int read(){register int x=0,f=1;register char c=getchar();while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();return x*f;}
#define INF 0x3f3f3f3f
using namespace std;
#define std std::ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
int gcd(int a,int b){
	return __gcd(a,b);
}
int qpow(int base,int index){int ret=1;while(index){if(index&1) ret=ret*base;index>>=1;base=base*base;} return ret;}
int lowbit(int x){return x&(-x);}
int dp[505][505];
int d[505],s[505];//d数组存位置,s数组存速度。
signed main(){
	int n,l,lim;cin>>n>>l>>lim;
	flr(i,1,n) cin>>d[i];
	flr(i,1,n) cin>>s[i];
	n++;d[n]=l;//让第n+1个点的距离为l,同时更新点的个数为n+1
	flr(i,1,n){
		flr(k,0,lim){
			dp[i][k]=dp[i-1][k]+(d[i]-d[i-1])*s[i-1];//初始化
		}
		frl(j,i-1,2){
			flr(k,0,lim){
				if(k+i-j<=lim) dp[i][k+i-j]=min(dp[i][k+i-j],dp[j-1][k]+(d[i]-d[j-1])*s[j-1]);
				else break;
			}	
		}
	}
	int ans=LLINF;
	flr(i,0,lim) ans=min(ans,dp[n][i]);//找到删除点的数目不超过k个点时花费时间最小的那种情况
	cout<<ans<<endl;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值