因为 除了终点外,中途点 位置 高度皆为 Y[1], 我们可以通过 横坐标唯一确定当前状态
所以 定义状态:
DP(I,K) 表示经过 第I栋 Building 移动到 K位置,最小 swap次数
则 转移方程为:
注意到, 因为我们是从 I = 1, 2, 3. ... ,N 顺序处理, dp(k)位置保存着 最优值, 所以第一维 I 我们可以省去
得到转移方程:
对于处理到 第I栋时, 枚举 Xi 到 最大横坐标 ,注意 非法状态的判定, 因为都是顺序处理的,若目前不合法,则后面状态也不合法
解题代码
View Code
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #define MAX(a,b) (a)>(b)?(a):(b) #define MIN(a,b) (a)<(b)?(a):(b) typedef long long LL; const int MAXN = 3000010; const int N = 5010; const int inf = 0x3f3f3f3f; int x[N],y[N]; int dp[MAXN]; int Max,ans, n; int main() { int T; scanf("%d",&T); while( T-- ) { scanf("%d", &n); Max = 0; for(int i = 1; i <= n; i++) { scanf("%d%d", &x[i], &y[i]); // 获取能跳跃到最远 横坐标 2*y[1]*y[i] - y[1]^2 = (y[1]-y[i])^2 - y[i]^2 Max = MAX( Max, x[i]+1 + (int)(sqrt(2.*y[1]*y[i]-y[1]*y[1])) ); } memset( dp, 0x3f, sizeof(dp) ); dp[ x[1] ] = 0; ans = inf; int h = y[1], flag = 0; for(int i = 2; i <= n; i++) { for(int k = x[i]; k <= Max; k++) { //因为swap后停下高度始终为 y[1] LL dx = k-x[i], dy = y[i]-h; if( dx*dx+dy*dy > 1LL*y[i]*y[i] ) break; if( 2*x[i]-k >= x[1] ) // swap的横坐标 大于等于 x[1] 才合法 dp[k] = MIN( dp[k], dp[ 2*x[i]-k ]+1 ); else break; // 因为K持续增大,若当前不合法,后面也都不合法 if( k >= x[n] && dp[k] < ans ) { flag = 1; ans = dp[k]; } } } printf("%d\n", flag? ans: -1 ); } return 0; }