题解 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;
}