动态规划 III——A - Railway tickets

其实大概的中心思想是:车从起始站出发,每到一个站就要票价最优化。如何最优化,就是每到的一个站,就要从这个站前面所有的站(到起始站为止)的相互相邻两两距离(不超过L3)来判断取哪个票价。两两距离取票价的判断从后往前推。

举个例子,比如我要的是2~6。

起始站是2,第一步:车子到的第一个站首先是3,那我要取3到2的距离,与L1、L2、L3进行比较,取最少的票价,最优化。

第二步:车子到的第二站是4,那我要取4到3的距离,与L1、L2、L3进行比较,取最少票价。然后我还要取3到2的最少票价,再与前面4到3所得的最少票价相加。保证了每一步票价的最优化。

第三步:车子到的第三站是5,那我要取5到4的距离,比较之后最少票价;还要取4到3,3到2的最少票价。一一往前递推,每一步都是票价的最优化。

第四步;车子到的第四站是6,那我就要取6到5,5到4,4到3,3到2的距离,并每一步取最少的票价,优化票价。

从中的到的规律是:大体上,站点从前往后推;局部里,站站两两距离从后往前推。同时,如果前面已最优化,后面推到前面时,如果前面最优化结果保存了下来,后面可直接使用。


#include<iostream>
#include<cmath>
using namespace std;
const int Max_l=10002;
const int inf=1<<30;
int dist[Max_l];    //dist[i]表示车站i与i-1的距离。(即车站i与它前一站的距离)
int d[Max_l];     //表示第i个车站到第一个车站的距离。
int dp[Max_l];    //dp[i]表示到车站i的最少票价。
int main()
{
	int L1,L2,L3,C1,C2,C3,n,m,from,to,i,j,k;
	while(cin>>L1>>L2>>L3>>C1>>C2>>C3)
	{
		cin>>n>>from>>to;
		if(from>to)                 //注意from和to的大小比较,题目没有默认大小。
		{
			int t=from;
			from=to;
			to=t;
		}
		dist[1]=0;                 //第1个车站距离它前一个车站的距离。
		d[1]=0;                    //第1个车站距离第1个车站的距离。
		for(i=2;i<=n;i++)   //表示从第2个车站(题目给出的距离是从这开始)起,到后面的第n个车站,距离第1个车站的距离。
		{
			scanf("%d",&d[i]);
			dist[i]=d[i]-d[i-1];  //表示从第2个车站起,到后面第n个车站,距离它前一个车站的距离。
		}
		for(i=0;i<=n;i++)
			dp[i]=inf;          //表示给到每一站票价的数组dp[i]赋最大值,方便后面求解到每一站票价的最小值。
		dp[from]=0;        //表示起始站票价初始化为零。(动态的边界)
		for(i=from+1;i<=to;i++)  //表示票价从起始站的后一站开始算起(因为乘客在起始站上车,所以从起始站到它的前一站的票价是不用计入其中,票价的计算从起始站的后一站开始算起,即是后一站到前一站的票价),一直到最后一个站。算每到一个站,与前一个站的最少票价。
		{
			int s=dist[i];    //S表示每一个站与它前一个站的距离。
		    for(j=i-1;s<=L3&&j>=from;s+=dist[j],j--)  //j表示从第i-1站一直推到起始站(递减);s是对相邻两站之间的距离进行累加;条件是每一次对前一站递推时,距离前一站的距离要在L3范围内(才有相应的票价可买,且每两个站的距离本来也不会超过L3的,题目有指明),且只能递推到起始站为止。
			{
				//下面是车从起始站出发后,每到达一站(以此往后递推),在这一站之前的“所有在它前面的站”(以此往前递推),从距离到达站的前一个站开始,判断到达站距离前一个站的距离,来确定最少的买票价格。
				if(0<s&&s<=L1)
					m=C1;
				if(L1<s&&s<=L2)
					m=C2;
				if(L2<s&&s<=L3)
					m=C3;
				dp[i]=min(dp[i],dp[j]+m);   //状态转移方程,注意,此前已经把所有dp[i]赋予很大值,此处体现出赋大值的作用,方便比较。
			}
		}
		cout<<dp[to]<<endl;
	}
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值