这道题要求我们在差最小的情况下反转次数最少。我们用dp[i][j]表示选取前i个股票,差值为j的最小反转。因为差最小是优先条件,所以我们完全可以找到最接近某一个值的点,取其最小反转次数。
那么dp[i][j] = min(dp[i-1][j+a[i]],dp[i-1][j-a[i]]+1),其中a[i]表示第i块骨牌上下点数之差(不是绝对值!!),所以你在取相反数的时候相当于反了过来。至于怎么解决负数的问题,好办,数据波动不超过5000,所以只要设置一个中间值(比如6000),把它设为开始开始DP,最后找一个最接近的即可。
看一下代码。
#include#include #include #include #include #include #include #define rep(i,a,n) for(int i = a;i <= n;i++)#define per(i,n,a) for(int i = n;i >= a;i--)#define enter putchar('\n')using namespace std;typedef long long ll;const int M = 20005;const int INF = 1000000009;int read(){ int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op;}int n,k,a[M],dp[1005][12005],x,y,minn = INF,ans;int main(){ n = read(); rep(i,1,n) x = read(),y = read(),a[i] = x - y; rep(i,0,n) rep(j,0,12000) dp[i][j] = INF; dp[0][6000] = 0; rep(i,1,n) { rep(j,1000,11000) { dp[i][j] = min(dp[i][j],dp[i-1][j+a[i]]); dp[i][j] = min(dp[i][j],dp[i-1][j-a[i]]+1); } } rep(j,1000,11000) { if(dp[n][j] == INF) continue; if(abs(6000 - j) < minn) minn = abs(6000-j),ans = dp[n][j]; } printf("%d\n",ans); return 0;}