状态压缩 - 动态规划 - LightOJ - 1011 - Marriage Ceremonies

本文介绍如何使用状态压缩动态规划解决在一个nXn矩阵中选取n个不同行不同列元素以获得最大和的问题。文章详细解释了状态压缩的概念,并给出具体的C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:[点这儿].

题意:

在一个n X n的矩阵中,选择n个数,这n个数所在的行列各不相同,求出这n个数的最大和. n<=16 .

解析:

看到这个题第一想法就是用KM算法做,能用KM算法做,那么就一定能用最小费用最大流做,这里不讨论这两种做法,讨论下动态规划的做法.

首先,这是个状态压缩动态规划的裸题,这里如果用搜索去做,会超时,而且会爆内存空间,因此,得把状态压缩到一个数中,正好,每一列选或不选对应01,故可以把这个状态压缩到16位的二进制数中;

dp[i][j]表示1~i行状态为j的最大和,这个时候只有j中二进制中1的个数等于ij状态是有效的,因为到第i行,只能选择i列,于是我们对合法的状态进行枚举,同时也枚举j状态中那么二进制位为0的列,那么很明显,状态转移方程为:

dpi+1,j|(1<<ibit)=max{dpi,j+arri,nibit1}(j&(1<<ibit)==0).

这种写法是由当前状态推下一种状态,而我们写得比较多的是前一种状态推当前状态.两种都要掌握.

代码:

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int T, K = 1;
    for (scanf("%d", &T); T--; K++) {
        int n, x;
        scanf("%d", &n);
        vector<vector<int> > arr(n + 1, vector<int>(n)), dp(n + 1, vector<int>(1 << n, 0));
        for (int i = 1; i <= n; i++)
            for (int j = 0; j < n; j++)
                arr[i][j] = (scanf("%d", &x), x);

        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < (1 << n); j++) {
                int cntOfOne = 0;
                for (int ibit = 0; ibit < n; cntOfOne += (j & (1 << ibit)) ? 1 : 0, ibit++);
                if (cntOfOne != i - 1)
                    continue;
                for (int ibit = 0; ibit < n; ibit++)
                    if (!(j & (1 << ibit)))
                        dp[i][j | (1 << ibit)] = max(dp[i][j | (1 << ibit)], dp[i - 1][j] + arr[i][n - ibit - 1]);
            }
        }

        printf("Case %d: %d\n", K, dp[n][(1 << n) - 1]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值