洛谷P1282 多米诺骨牌 【dp】

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

题意

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

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

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

题解

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

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

预处理每个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;
}

posted @   SxtoxA  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
12 13
点击右上角即可分享
微信分享提示