HDU 5935 Car【贪心,枚举,精度】
Problem Description
Ruins is driving a car to participating in a programming contest. As on a very tight schedule, he will drive the car without any slow down, so the speed of the car is non-decrease real number.
Of course, his speeding caught the attention of the traffic police. Police record N positions of Ruins without time mark, the only thing they know is every position is recorded at an integer time point and Ruins started at 0.
Now they want to know the minimum time that Ruins used to pass the last position.
Input
First line contains an integer T, which indicates the number of test cases.
Every test case begins with an integers N, which is the number of the recorded positions.
The second line contains N numbers a1, a2, ⋯, aN, indicating the recorded positions.
Limits
1≤T≤100
1≤N≤105
0< ai≤109
ai< ai+1
Output
For every test case, you should output ‘Case #x: y’, where x indicates the case number and counts from 1 and y is the minimum time.
Sample Input
1
3
6 11 21
Sample Output
Case #1: 4
【题意】:给一些距离点,要求速度(real number)非递减,求从0开始到最后一点的最少时间。eg:(6)6(5)11(10)21 , 要时间最少,最后一段为1s,中段5/5=1,最前为6/3=2(因为保持速度非递减)。1+1+2=4。
【分析】:贪心。从后往前推,因为没有给出对速度的限制,最后一段时间最小必定为1s,通过已经预设的1s可以求得最后一段的速度。又要保持速度非递减,可以枚举时间1s,2s,3s···,直到速度小于等于后一段的就可以。时间是个整数,但是速度不一定是个整数。于是精度问题要格外小心。
【代码】:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<string.h> #include<cstdio> #include<iostream> #define maxn 100005 int main() { int t; int n,sum; int a[maxn]; scanf("%d",&t); for(int cas=1;cas<=t;cas++) { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); double v=(a[n]-a[n-1]); sum=1; for(int i=n-1;i>=1;i--) { for(int j=(a[i]-a[i-1])/v; ;j++) { double y=(a[i]-a[i-1])*1.0/j; if(y<=v) { sum+=j; v=y; break; } } } printf("Case #%d: %d\n",cas,sum); } return 0; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; #define eps 1e-8 int s[100005]; int main() { int t,n,x,ans,tt=1; double v; scanf("%d",&t); while(t--) { scanf("%d",&n); ans=1; for(int i=1;i<=n;i++) scanf("%d",&s[i]); v=s[n]-s[n-1]; for(int i=n-1;i;i--) { x=s[i]-s[i-1]; if(x<=v+eps) { ans++; v=x; } else { ans+=(int(double(x-eps)/v)+1); v=double(x)/(int(double(x-eps)/v)+1); } } printf("Case #%d: %d\n",tt++,ans); } return 0; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> using namespace std; typedef long long ll; const int maxn = 1e5+5; int a[maxn], t, n, ca = 1; int main(void) { cin >> t; while(t--) { scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); ll ans = 0; double spe = a[n]-a[n-1]; for(int i = n; i > 0; i--) { double len = (a[i]-a[i-1])*1.0; int t = len/spe; ans += t; if(len/t != spe) { ans++; spe = len/(t+1); } } printf("Case #%d: %d\n", ca++, ans); } return 0; }
*********************************************别人的想法:http://blog.csdn.net/queuelovestack/article/details/52984042
由于车速是非递减的,那么从第N-1个位置到第N个位置最优的用时为1
对于相邻的两段,我们有
稍微做个转化,可得
即相同时间间隔内,后者所驶过的路程要大于等于前者
已知最后一段行驶时间间隔为1,行驶路程为a[n]-a[n-1]
倒数第二段行驶路程为a[n-1]-a[n-2]
则倒数第二段的行驶时间间隔为
得到倒数第二项之后可以由倒数第二项推出倒数第三项
反向遍历一遍即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> #include<stack> #include<math.h> #include<vector> #include<map> #include<set> #include<list> #include<bitset> #include<cmath> #include<complex> #include<string> #include<algorithm> #include<iostream> #define eps 1e-9 #define LL long long #define PI acos(-1.0) #define bitnum(a) __builtin_popcount(a) using namespace std; const int N = 100005; const int M = 100005; const int inf = 1000000007; const int mod = 1000000007; int s[N]; int main() { int t,n,i,j,p=1; __int64 ans,a,b,c; scanf("%d",&t); while(t--) { ans=0; scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&s[i]); a=s[n]-s[n-1];b=1; for(i=n;i>=1;i--) { c=s[i]-s[i-1]; b=(b*c+a-1)/a; a=c; ans+=b; } printf("Case #%d: %I64d\n",p++,ans); } return 0; }