这个题的转移状态不好想:
设f[i][j]为:在第i个数,当前位置与开头位置距离为j时,end位置的最小值
我们不需要确定最左端位置在哪里,只要知道相对位置就好了,可以想做将他们平移到零点
每次更新我们只要枚举和开始节点的长度 j 进行更新,注意到一点特征,ai<=1000,那么距离 j 肯定是 j<=2000的,可以想一下为什么,详细请看代码:
#include<bits/stdc++.h> using namespace std; int n,k; int a[10005]; int dp[10005][2005]; void run() { int n; cin>>n; for(int i = 0; i<n+2; i++)for(int j =0; j<=2002; j++)dp[i][j]=99999999; for(int i=1; i<=n; i++) { cin>>a[i]; } dp[1][a[1]]=a[1]; for(int i=2; i<=n; i++) { for(int j = 0; j<=2000; j++) { if(a[i]+j<dp[i-1][j]) dp[i][a[i]+j]=min(dp[i][a[i]+j],dp[i-1][j]); else { if(a[i]+j<=2000) dp[i][a[i]+j]=min(a[i]+j,dp[i][a[i]+j]); } if(a[i]<j) { dp[i][j-a[i]]=min(dp[i][j-a[i]],dp[i-1][j]); } else { if(a[i]-j+dp[i-1][j]<=2000) dp[i][0]=min(dp[i][0],a[i]-j+dp[i-1][j]); } } } int ans =99999999; for(int i =0; i<=2000; i++) { ans=min(ans,dp[n][i]); } cout<<ans<<endl; } int main() { int t; cin>>t; while(t--) run(); return 0; }