luogu P1282 多米诺骨牌

题解

线性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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值