luogu P1282 多米诺骨牌

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/smmyy022/article/details/81782587

题解

线性dp,需要一点理解。可以类比背包问题,此时的状态不是背包容量而是差值。
f [i][j]:代表对前 i 个牌在 j 的差值下 最小的翻动数。
有递推式
f [ i ] [ j ] = min( f [ i - 1 ] [ j - (a[i]-b[i]) ]+1 , f [ i - 1 ] [ j - (b[i]-a[i]) ] )
a[],b[] 为上下牌面数

ps: 显然 j 差值可能为负,编程时加个偏移量使之为正即可。


Code

//  head file excluded
using namespace std;

int n,m;
const int NN = 5000;// 向后位移 保证差值为正
int f[2][NN*2+1];
int a[1001],b[1001];
int main(){

    cin>>n;

    int border = 0;
    for(int i=1;i<=n;i++) {
        cin>>a[i]>>b[i];
        border += abs(a[i] - b[i]);
    }

    memset(f,0x7f,sizeof(f));
    f[0][0+NN]=0;

    int tar=0,ori = 1;// 两数组交替存储
    for(int i=1;i<=n;i++){
        tar^=1,ori^=1;
        for(int j=-border;j<=border;j++){
            f[tar][j+NN] = min( f[ori][NN+j-a[i]+b[i]]+1,
                        f[ori][NN+j-b[i]+a[i]] );
        }
    }

    int ans;
    for(int j=0;j<=border;j++){ // 最小到边缘移动 第一个非INF即可
        ans = min( f[n&1][NN+j], f[n&1][NN-j] );
        if(ans <= 1000){
            cout<<ans<<endl;
            break;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/smmyy022/article/details/81782587