a[i+1]:
=a[i];
end;
c:
=c+a[i]*s;
end;
end;
writeln(c);
close(input);
close(output);
end.
【例3-5】旅行家的预算
【问题描述】
一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。
给定两个城市的距离Dic1,汽车油箱的容量C(以升为单位),每升汽油能行驶的距离Dic2,出发时每升油的价格为p。
沿途有n个油站(1<=n<=100),油站i离出发点的距离di,该油站每升汽油的价格pi(i=1,2,…,n)。
请编程输出完成任务的最小费用,计算结果四舍五入这小数点后两位,如果无法到达目的地,则输出“Nosolution”。
输入:
输入文件名为:
oil.in,共n+1行,第一行为:
Dic1CDic2Pn,以下n行,其中第i+1(1<=i<=n)行的数据均有2个:
该油站据出发点的距离di,该油站每升汽油的价格pi。
每个数据之间用一个空格隔开。
输出:
输出文件名为:
oil.out,仅一行,表示最小费用。
【样例输入】
275.611.927.42.82
102.02.9
220.02.2
【样例输出】
26.95
【题解】
设出发的城市为0站,目的城市为n+1站。
汽车目前在i站(0<=i<=n),应加多少油,驶往那一站可是整个行程的花费最少?
我们不妨采用下面的贪心策略:
下一个目的站的单位油价尽可能低于i站,如果所有可达油站的单位油价都高于i站的话,则下一个目的站的油价也应该尽可能的便宜。
【标程】
第一种解法:
#include
usingnamespacestd;
doubled1,c,d2,p,a[20000]={0},b[20000]={0},count=0;
intmain()
{
intn,i,j,k;
doublemin,pre=0;
scanf("%lf%lf%lf%lf%d",&d1,&c,&d2,&p,&n);
a[0]=p;b[n+1]=d1;
for(i=1;i<=n;i++)
scanf("%lf%lf",&b[i],&a[i]);
for(i=0;i{
a[n+1]=a[i];min=1000000.0;
if(b[i+1]-b[i]>c*d2)
{
printf("NoSolution\n");
return0;
}
for(j=i+1;b[j]-b[i]<=c*d2&&j<=n+1;j++)
if(a[j]<=min){min=a[j];k=j;}
if(a[k]<=a[i])
{
if(pre*d2
{
count+=a[i]*((b[k]-b[i])/d2-pre);
pre=0;
}
elsepre-=(b[k]-b[i])/d2;
}
else
{
count+=(c-pre)*a[i];
pre=c-(b[k]-b[i])/d2;
}
i=k;
}
printf("%.2lf\n",count);
return0;
}
第二种解法:
#include
#include
usingnamespacestd;
#definemaxn102
doubled[maxn];
doublec;
doubled2;
doublep[maxn];
intn;
doublecost;
doublerest;
intmain()
{
doubled1;
scanf("%lf%lf%lf%lf%d",&d1,&c,&d2,&p[0],&n);
for(inti=1;i<=n;i++)
{
scanf("%lf%lf",&d[i],&p[i]);
}
d[n+1]=d1;
p[n+1]=0;
d[0]=0;
cost=0;
rest=0;
intk=0;
while(k<=n)
{
intj=k;
intflag=0;
intmin=0;
doubleneed=0;
while(d[j+1]-d[k]<=c*d2&&j<=n)
{
j++;
if(flag==0&&p[j]
{
flag=j;
}
if(min==0||p[j]
{
min=j;
}
}
if(k==j)
{
printf("NoSolution\n");
return0;
}
if(flag==0)
{
need=c-rest;
cost+=need*p[k];
rest=c-(d[min]-d[k])/d2;
k=min;
}
else
{
need=(d[flag]-d[k])/d2-rest;
if(need<0)
{
need=0;
}
cost+=need*p[k];
rest=0;
k=flag;
}
}
printf("%0.2lf\n",cost);
return0;
}
【例3-6】线段覆盖
【问题描述】
给定x轴上的N(0每个线段由他的两个端点ai和bi确定,i=1,2,……,N。
这些坐标都是区间(-999,999)的整数。
有些线段会相互交叠或覆盖。
请你编写一个程序,从给出的线段中去掉尽量少的线段,使得剩下的线段之间两两之间没有内部公共点。
输入:
输入文件名为:
cover.in。
第一行是一个整数n。
接下来又n行,每行有两个空格隔开的整数,表示一条线段的两个端点的坐标。
输出:
输出文件名为:
cover.out,第一行是一个整数表示最多剩下的线段数。
接下来有这么多行(按照坐标升序排列剩下的线段),每行两个整数分别表示一条线段的左端点和右端点。
如果有多解,只需输出其中一组解即可。
【样例输入】
3
63
13
25
【样例输出】
2
【题解】
我们选取的贪心策略为:
每次选取线段右端点坐标最小的线段,保留这条线段,并把和这条线段有共部分的所有线段删除。
重复这个过程,直到任两条线段之间多没有公共部分。
【标程】
#include
#include
#include
usingnamespacestd;
structstu
{
intl;
intr;
}a[1001];
boolcmp(stux,stuy)
{
returnx.r}
intmain()
{
intn;
intans;
scanf("%d",&n);
ans=n;
for(inti=0;i{
scanf("%d%d",&a[i].l,&a[i].r);
if(a[i].l>a[i].r)swap(a[i].l,a[i].r);
}
sort(a+0,a+n,cmp);
inti=0;//i用来记录当前位置的线段
intss=1;
while(i+ss{
if(a[i].r<=a[i+ss].l&&(i+ss{
i=i+ss;//更新状态,跳到与之比较的线段
ss=1;
}
elseif(a[i].r>a[i+ss].l&&a[i].r<=a[i+ss].r&&(i+ss{
ans--;
ss++;
}
elseif(a[i].r>a[i+ss].l&&a[i].r>a[i+ss].r&&(i+ss{
ans--;
i++;
ss=1;
}
}
printf("%d",ans);
return0;
}
【例3-7】智力大冲浪
【问题描述】
小伟报名参加中央电视台的智力大冲浪节目。
本次挑战赛吸引了众多参赛者,主持人为了表彰大家的勇气,先奖励每个参赛者m元。
先不要太高兴!
因为这些钱还不一定都是你的?
!
接下来主持人宣布了比赛规则:
首先,比赛时间分为n个时段(n≤500),它又给出了很多小游戏,每个小游戏都必须在规定期限ti前完成(1≤ti≤n)。
如果一个游戏没能在规定期限前完成,则要从奖励费m元中扣去一部分钱wi,wi为自然数,不同的游戏扣去的钱是不一样的。
当然,每个游戏本身都很简单,保证每个参赛者都能在一个时段内完成,而且都必须从整时段开始。
主持人只是想考考每个参赛者如何安排组织自己做游戏的顺序。
作为参赛者,小伟很想赢得冠军,当然更想赢取最多的钱!
注意:
比赛绝对不会让参赛者赔钱!
【输入】
输入文件riddle.in,共4行。
第1行为m,表示一开始奖励给每位参赛者的钱;
第2行为n,表示有n个小游戏;
第3行有n个数,分别表示游戏1到n的规定完成期限;
第4行有n个数,分别表示游戏1到n不能在规定期限前完成的扣款数。
【输出】
输出文件riddle.out,仅1行。
表示小伟能赢取最多的钱。
【样例】
riddle.inriddle.out
100009950
7
4243146
70605040302010
【题解】
这题有两种贪心策略:
①根据扣款数排序,让扣款数大的尽量准时完成。
对于每个游戏i,尽量将其放在[1..t[i]]中最大的空闲时间,若不能放,则放到最大的空闲时间。
②根据时限排序,从1开始扫描,一旦i这个游戏不能完成,那么从1..i中选取一个扣款数最小的舍去
我的代码中用的是第二种贪心策略。
#include
#include
#include
#include
usingnamespacestd;
intmain()
{
intm,n,p,min,minx,total,i,j,w[600],t[600],q[600];
memset(q,0,sizeof(q));
memset(w,0,sizeof(w));
memset(t,0,sizeof(t));
scanf("%d%d",&m,&n);
for(i=1;i<=n;i++)
scanf("%d",&t[i]);
for(i=1;i<=n;i++)
{
scanf("%d",