好题!
第一眼就感觉是dp。
设dp[i][j]表示到第i个位置上面-下面为j的最小步数。
可以发现,这里由于上面-下面可能是负的。
那么单纯去dp显然不行。
这里就用到了一个思想,零点转移。
因为差距最多在5,6000左右,我们设6000为0点,那么-T就变成了6000-T。
然后就可以去dp了,正负分开下判断即可。
// Author: levil #include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 1e3+5; const int M = 2e4+5; const LL Mod = 1e9+7; #define rg register #define pi acos(-1) #define INF 1e9 #define CT0 cin.tie(0),cout.tie(0) #define IO ios::sync_with_stdio(false) #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } void print(int x){ if(x < 0){x = -x;putchar('-');} if(x > 9) print(x/10); putchar(x%10+'0'); } } using namespace FASTIO; void FRE(){/*freopen("data1.in","r",stdin); freopen("data1.out","w",stdout);*/} int a[1005],b[1005],dp[N][12005]; int main() { int n;n = read(); for(int i = 1;i <= n;++i) a[i] = read(),b[i] = read(); for(int i = 0;i <= n;++i) for(int j = 0;j <= 12005;++j) dp[i][j] = INF; dp[0][6000] = 0; for(int i = 1;i <= n;++i) { int dis = a[i]-b[i]; if(dis >= 0) { for(int j = 12000;j >= 0;--j) if(j-dis >= 0) dp[i][j] = min(dp[i][j],dp[i-1][j-dis]); dis = -dis; for(int j = 0;j <= 12000;++j) if(j-dis <= 12000) dp[i][j] = min(dp[i][j],dp[i-1][j-dis]+1); } else { for(int j = 0;j <= 12000;++j) if(j-dis <= 12000) dp[i][j] = min(dp[i][j],dp[i-1][j-dis]); dis = -dis; for(int j = 12000;j >= 0;--j) if(j-dis >= 0) dp[i][j] = min(dp[i][j],dp[i-1][j-dis]+1); } } int ans = INF,step; for(int i = 0;i <= 12000;++i) { if((abs(i-6000) < ans && dp[n][i] != INF) || (abs(i-6000) == ans && dp[n][i] < step)) ans = abs(i-6000),step = dp[n][i]; } printf("%d ",step); system("pause"); }