【算法实验四】(DP-动态规划)【旅游预算】

1149.旅游预算

时限:1000ms 内存限制:10000K  总时限:3000ms

描述

一个旅行社需要估算乘汽车从某城市到另一城市的最小费用,沿路有若干加油站,每个加油站收费不一定相同。旅游预算有如下规则: 若油箱的油过半,不停车加油,除非油箱中的油不可支持到下一站;每次加油时都加满;在一个加油站加油时,司机要花费2元买东西吃;司机不必为其他意外情况而准备额外的油;汽车开出时在起点加满油箱;计算精确到分(1元=100分)。编写程序估计实际行驶在某路线所需的最小费用。

 

输入

第一行为起点到终点的距离(实数) 第二行为三个实数,后跟一个整数,每两个数据间用一个空格隔开。其中第一个数为汽车油箱的容量(升),第二个数是每升汽油行驶的公里数,第三个数是在起点加满油箱的费用(精确到分),第四个数是加油站的数量。(〈=50)。接下去的每行包括两个实数,每个数据之间用一个空格分隔,其中第一个数是该加油站离起点的距离,第二个数是该加油站每升汽油的价格(元/升)。加油站按它们与起点的距离升序排列。所有的输入都有一定有解。

 

输出

共两行,每行都有换行 第一行为一个实数和一个整数,实数为旅行的最小费用,以元为单位,精确到分,整数表示途中加油的站的N。第二行是N个整数,表示N个加油的站的编号,按升序排列。数据间用一个空格分隔,最后一个数据后也输出空格,此外没有多余的空格。

 

输入样例

516.3 15.7 22.1 20.87 3 125.4 1.259 297.9 1.129 345.2 0.999

 

输出样例

38.09 1 2

#include<iostream>
//#include<float.h>
#include<stdio.h>
#define DBL_MAX 1.7976931348623158e+308
using namespace std;
/************************/
int n;
double length;
double cap,mile,cost;
double dist[51],prize[51];
/************************/
int addoil[51];
double memo[51];//备忘录
double maxdist; //the max dist after pour in oil
/***********************/
double dp(int i);
double dp(int i)
{
	if(i==n+1)
		return cost;
	else if(memo[i]!=DBL_MAX)
		return memo[i];
	else
	{
		double fuel_j; //fuel from i to j
		double fuel_rest; //the rest fuel after from i to j
		double cost_j; //from i to j and add oil in j
		double cost_j_n; //total cost from i to j to end
		int addoil_j=-1; //the station need to add oil
		for(int j=i+1;j<=n+1 && (dist[j]-dist[i])<=maxdist;j++)
		{
			fuel_j=(dist[j]-dist[i])/mile;
			fuel_rest=cap-fuel_j;
			if(fuel_rest>cap/2 && fuel_rest*mile>=(dist[j+1]-dist[j]))
				continue;
			if(j==n+1)
				cost_j=0;
			else
			{
				cost_j=2;
				cost_j+=fuel_j*prize[j]; //消耗的油*油价=加满油
			}

			cost_j_n=cost_j+dp(j);

			if(memo[i]>cost_j_n)
			{
				memo[i]=cost_j_n;
				addoil_j=j;
			}
		}
		if(addoil_j!=-1)
			addoil[addoil_j]=1;
		return memo[i];
	}
}

int main()
{
	int count=0;
	cin>>length;//input
	cin>>cap>>mile>>cost>>n;
	int i=1;
	while(i<=n)
	{
		cin>>dist[i]>>prize[i];
		i++;
	}
	for(int i=0;i<=n;i++)
	{
		memo[i]=DBL_MAX;
	}
	dist[0]=0;
	dist[n+1]=length;
	maxdist=cap*mile;//

	double mincost=dp(0);

	printf("%.2lf ",mincost);//first line
	for(int i=1;i<=n;i++)
	{
		if(addoil[i])
			count++;
	}
	cout<<count<<endl;//second line
	for(int i=1;i<=n;i++)
	{
		if(addoil[i])
			cout<<i<<" ";
	}
	cout<<endl;//
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值