多米诺骨牌

传送门

这道题要求我们在差最小的情况下反转次数最少。我们用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<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#include<queue>
#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;
}

 

posted @ 2018-10-26 23:40  CaptainLi  阅读(159)  评论(0编辑  收藏  举报