首页 > 其他分享 >洛谷P1282 多米诺骨牌 【dp】

洛谷P1282 多米诺骨牌 【dp】

时间:2023-01-09 12:14:13浏览次数:75  
标签:洛谷 多米诺骨牌 int 最小 maxn P1282 点数 dp

参考:
https://blog.csdn.net/qq_51354600/article/details/120623720

题意

给定\(n\)个多米诺骨牌,每个多米诺骨牌由上下两部分组成,每部分的点数为\(1 \sim 6\)中的某一个数且已给定。

记上下\(2\)行点数之差为上部分的点数之和-下部分的点数之和。

每一个多米诺骨牌可以执行操作使得上下交换,求最小交换次数使得上下\(2\)行点数最小

题解

求最小点数的最小交换次数->求每个点数下的最小交换次数

令\(dp[i][j]\)表示前\(i\)个多米诺骨牌,上部分的点数和为\(j\)下的最小交换次数。假设\(sum\)为上下两部分的点数总和,那么点数之差可以表示为\(|j-(sum-j)|\)。

预处理每个\(j\)下的最小交换次数,类似背包问题,要么选择上部分点数以加入,要么交换一次以加入下部分点数。

枚举每个\(j\),优先更新最小的点数差,如果点数差相等则更新最小交换次数。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>

const int maxn = 1000 + 10;
const int inf = 0x3f3f3f3f;
int n;
int sum;
int a[maxn], b[maxn];
int dp[maxn][6 * maxn];
int res = 0, minus = inf;

signed main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d%d", &a[i], &b[i]);
        sum += a[i] + b[i];
    }
    memset(dp, inf, sizeof(dp));
    dp[0][0] = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= 6 * i; j++) {
            if (j >= a[i]) dp[i][j] = std::min(dp[i][j], dp[i - 1][j - a[i]]);
            if (j >= b[i]) dp[i][j] = std::min(dp[i][j], dp[i - 1][j - b[i]] + 1);
        }

    for (int i = n; i <= 6 * n; i++) {
        int temp = abs(i - (sum - i));
        if (temp < minus) {
            minus = temp;//更新最小差值
            res = dp[n][i];
        } else if (temp == minus) res = std::min(res, dp[n][i]);
    }

    printf("%d", res);
    return 0;
}

标签:洛谷,多米诺骨牌,int,最小,maxn,P1282,点数,dp
From: https://www.cnblogs.com/MrWangnacl/p/17036629.html

相关文章