题目链接:http://poj.org/problem?id=1925
题意:给出N个点,每个点都有两个数x、y,其中x表示点的横坐标,y表示纵坐标(建筑物的高度);给出的每个点都满足y值是大于等于起始点的y值;并且这些点是按照x升序排列的。
现在让你求:蜘蛛侠在起始点(第一个点),他想去终点(第N个点),问他最少要吐多少次丝!(他不能触碰到地,但是可以刚好相等)!
分析:DP
dp[i]表示 :到x[i]需要的最少次数。
很容易得到,蜘蛛侠一直是在y1高度(可以低于,但不能超过,能量守恒),为了能最少吐丝次数,那么他肯定是保持y1的高度的!
由于他不能触碰到地,我们可以等处这样一个关系式:dis^2<=(yi*yi-(yi-y1)*(yi-y1));dis表示从左边开始到i点的距离,因此当我们在i点的时候我们可以选取的范围j是: [ x[i]-dis,x[i]-1 ]。
从对称性可以知道:距离为j,对称点为i点是的距离是temp=2*x[i]-j。
因此我们可以得出方程:dp[i]=min(dp[temp]+1);(初始值为inff,dp[x[1]]=0)
值得注意的是到距离temp>=x[n]的时候temp=x[n];
1 #include<cstdio> 2 #include<iostream> 3 #include<map> 4 #include<string.h> 5 #include<algorithm> 6 using namespace std; 7 typedef long long ll; 8 const int inff=1e9+7; 9 const int maxn=2e6+10; 10 int dp[maxn]; 11 int x[6000],y[6000]; 12 ll dis[6000]; 13 int n; 14 int main() 15 { 16 int t; 17 scanf("%d",&t); 18 while(t--){ 19 scanf("%d",&n); 20 21 for(int i=1;i<=n;i++){ 22 scanf("%d %d",&x[i],&y[i]); 23 dis[i]=y[i]*y[i]-(y[i]-y[1])*(y[i]-y[1]); 24 } 25 for(int i=0;i<=x[n];i++) 26 dp[i]=inff; 27 dp[x[1]]=0; 28 for(int i=2;i<=n;i++){ 29 for(int j=x[i]-1;j>=x[1];j--){ 30 if(dp[j]==inff)continue; 31 if((x[i]-j)*(x[i]-j)>dis[i])break; 32 33 int temp=2*x[i]-j; 34 35 dp[temp]=min(dp[temp],dp[j]+1); 36 if(temp>=x[n]) 37 dp[x[n]]=min(dp[x[n]],dp[j]+1); 38 39 } 40 } 41 if(dp[x[n]]==inff) 42 printf("-1\n"); 43 else 44 printf("%d\n",dp[x[n]]); 45 } 46 return 0; 47 }
还有种初始值为-1,判断的,其实两种都是一样的,只是-1这个判断语句要多一点!~~!~
最坑的是请注意使用scanf、printf;不是使用cin、cout输入输出,这道题cin、cout会超时,疯狂TLE;