题解 P1016 【旅行家的预算】

贪心题

贪心算法
可以证明,在一般情况下,可以找身前最小点,然后算总量+=(两点距离)/每升油跑的路程 乘上 此点油价
但是!
我是说“在一般情况下”
我此前WA了一个点 75
理由是没有考虑前点价小于后点能到达的所有价
此时应该考虑把油加满,用nspc和lnspc记录箱内油量
可是问题并未结束,如果不加满就可以到终点怎么办?此时就要看我代码了
关于出现三次的goto:这里科普
我相信我的变量命名简洁易懂
应该看得懂的蒟蒻的代码:


#include<bits/stdc++.h>
using namespace std;
int n,now,bj;
double S,spc,perS,v[10],dis[10],total,nspc,tem,lnspc;
//S路程,perS每升路程,v价格,dis路程,spc=spc,nspc=nowspace,lnspc=lastnowspace
int find_cheapest(int x,int y)
{
	double maxx=1001;
	int maxn=0;
	for(int i=x;i<=y;i++)
	{
		if(v[i]<maxx)
		{
			maxx=v[i];
			maxn=i;
		}
	}
	return maxn;
}
int main()
{
	//freopen("travel.in","r",stdin);
	//freopen("travel.out","w",stdout);
	cin>>S>>spc>>perS>>v[0]>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>dis[i]>>v[i];
	}
	dis[n+1]=S;
	v[n+1]=9999;//将终点视为n+1
	n++;
	for(int i=1;i<=n;i++)//排除到达不了的情况 
		if((dis[i]-dis[i-1])/perS>spc)
		{
			cout<<"No Solution";
			return 0;
		}
	for(;;)//不到终点非好汉,所以使劲跑,反正排除了No Solution
	{
		for(int j=n;j>=now+1;j--)
		{
			int tmp=find_cheapest(now+1,j);//找身前最小点
			if(v[tmp]>v[now])//我说的WA掉的关键,判断与当前点油价比是否更小
			{
				nspc=spc;
				bj=1;
				goto Wzz;//玄学的跳法。。。只能慢慢体会
				Orz:
				total+=nspc*v[now];
				nspc-=(dis[tmp]-dis[now])/perS;
				lnspc=nspc;
				now=tmp;
			}
			else
			{
				bj=0;
				if((dis[tmp]-dis[now])/perS<=spc)
				{
					tem=(dis[tmp]-dis[now])/perS;
					total+=(tem-nspc)*v[now];
					nspc=0;
					now=tmp;
					Wzz:
					if(spc*perS>=dis[n]-dis[now])
					{
						total+=((dis[n]-dis[now])/perS-lnspc)*v[now];
						goto stop;//stop用来跳出循环输出结果
					}
					else
					{
						if(bj==1)
							goto Orz;
					}
					break;
				}
			}	
		}			
	}
	stop:
	printf("%.2lf",total);
	return 0;
}
posted @ 2019-01-24 20:07  G_A_TS  阅读(429)  评论(0编辑  收藏  举报