LeetCode 1349. 参加考试的最大学生数 (状压DP 或 二分图最大独立子集)
给你一个 m * n 的矩阵 seats 表示教室中的座位分布。如果座位是坏的(不可用),就用 '#' 表示;否则,用 '.' 表示。
学生可以看到左侧、右侧、左上、右上这四个方向上紧邻他的学生的答卷,但是看不到直接坐在他前面或者后面的学生的答卷。请你计算并返回该考场可以容纳的一起参加考试且无法作弊的最大学生人数。
学生必须坐在状况良好的座位上。
示例 1:

输入:seats = [["#",".","#","#",".","#"],
[".","#","#","#","#","."],
["#",".","#","#",".","#"]]
输出:4
解释:教师可以让 4 个学生坐在可用的座位上,这样他们就无法在考试中作弊。
提示
seats 只包含字符 '.' 和'#'
m == seats.length
n == seats[i].length
1 <= m <= 8
1 <= n <= 8
1. 状压DP
首先一看数据范围,一个学过状压DP的人就应该想到它……个人经验,数据范围在 10 左右的时候,就可以考虑下是不是状压DP。
用二进制的每一位去枚举一个位置是否坐了人,一行有n个座位,则一共有1<<n种情况。
dp[i][j]用来第i行状态为j的最大值,那么dp[i][j]=j状态包含1的个数+max(dp[i-1][k]) (0<=k<(1<<n) && j 和 k 都是合法状态 && j和k不存在能够相互抄袭的两个位置)
比赛时代码写的比较丑陋 写80多行……赛后参考了一下题解,使用 j&(j<<1) 来判断是否有相邻的点就比较厉害了~
AC代码(cpp)
class Solution {
int countOne(int x) {
int cnt = 0;
while(x != 0) x = x & (x - 1), cnt++;
return cnt;
}
public:
int maxStudents(vector<vector<char>>& seats) {
int n = seats.size();
int m = seats[0].size();
int st = 1 << m;
vector<vector<int>> dp(n, vector<int>(st, 0));
for (int i = 0; i < n; i++) {
int mask = 0;
for (int j = 0; j < m; j++) {
mask += seats[i][j] == '#' ? (1 << j) : 0;
}
for (int j = 0; j < st; j++) {
if (!(j & mask) && !(j & (j << 1))) {
int v = countOne(j);
if (i == 0) dp[i][j] = v;
else {
for (int k = 0; k < st; k++) {
if (!((k << 1) & j) && !((k >> 1) & j)) {
dp[i][j] = max(dp[i][j], dp[i - 1][k] + v);
}
}
}
}
}
}
int ans = 0;
for (int i = 0; i < st; i++) {
ans = max(dp[n - 1][i], ans);
}
return ans;
}
};
2. 二分图最大匹配
太久没有写过二分图已经没什么印象了,经群里大神提示,才又复习了一遍之前的博客。
此题如果把每个能抄袭的两个位置连接,求最大可以容纳的考生数就是求没内部有边的最大集合,即最大独立子集。
同时又知道二分图属性
最大独立数 = 顶点数 — 最大匹配数
那么此题转化为求二分图最大匹配。
有一点需要注意的是,匈牙利模板中,是将两个点集分开的情况下去求最大匹配的,而类似本题是没有规定哪个点属于哪个点集,
所以可以想象把每个点拆成两个点,每个点属于一个子集,这样才是最大匹配算法对应的结果。
而对于原集合来说,最大匹配答案应该 /2。
AC代码(cpp)
class Solution {
static const int N = 64;
vector<int> G[N];
bool used[N];
int match[N];
int r, c, n;
int id(int row, int col) {
return row * c + col;
}
void join(int x, int y) {
G[x].push_back(y);
G[y].push_back(x);
}
bool findPath(int u) {
for (int v: G[u]) {
if (used[v]) continue;
used[v] = true;
if (match[v] == -1 || findPath(match[v])) {
match[v] = u;
return true;
}
}
return false;
}
public:
int maxStudents(vector<vector<char>>& seats) {
r = seats.size(), c = seats[0].size(), n = r * c;
int total = 0;
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (seats[i][j] == '.') {
total++;
if (i > 0) {
if (j > 0 && seats[i - 1][j - 1] == '.') { // 左上
join(id(i, j), id(i - 1, j - 1));
}
if (j + 1 < c && seats[i - 1][j + 1] == '.') { // 右上
join(id(i, j), id(i - 1, j + 1));
}
}
if (j > 0 && seats[i][j - 1] == '.') { // 左侧
join(id(i, j), id(i, j - 1));
}
}
}
}
int matchNum = 0;
memset(match, -1, sizeof match);
for (int i = 0; i < n; i++) {
memset(used, false, sizeof used);
if (findPath(i)) ++matchNum;
}
return total - matchNum / 2;
}
};
LeetCode 1349. 参加考试的最大学生数 (状压DP 或 二分图最大独立子集)的更多相关文章
- HDU 1565 - 方格取数(1) - [状压DP][网络流 - 最大点权独立集和最小点权覆盖集]
题目链接:https://cn.vjudge.net/problem/HDU-1565 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32 ...
- 【BZOJ5010】【FJOI2017】矩阵填数 [状压DP]
矩阵填数 Time Limit: 10 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description 给定一个 h*w 的矩阵,矩阵的行 ...
- BZOJ 2734 [HNOI2012]集合选数 (状压DP、时间复杂度分析)
题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2734 题解 嗯早就想写的题,昨天因为某些不可告人的原因(大雾)把这题写了,今天再来写题解 ...
- 洛谷$P3226\ [HNOI2012]$集合选数 状压$dp$
正解:$dp$ 解题报告: 传送门$QwQ$ 考虑列一个横坐标为比值为2的等比数列,纵坐标为比值为3的等比数列的表格.发现每个数要选就等价于它的上下左右不能选. 于是就是个状压$dp$板子了$QwQ$ ...
- $HNOI2012\ $ 集合选数 状压$dp$
\(Des\) 求对于正整数\(n\leq 1e5\),{\(1,2,3,...,n\)}的满足约束条件:"若\(x\)在该子集中,则\(2x\)和\(3x\)不在该子集中."的子 ...
- HDU 1565 方格取数 状压dp
题目: 给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大. Input 包括多 ...
- 【BZOJ-2732】集合选数 状压DP (思路题)
2734: [HNOI2012]集合选数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1070 Solved: 623[Submit][Statu ...
- [HNOI2012]集合选数 --- 状压DP
[HNOI2012]集合选数 题目描述 <集合论与图论>这门课程有一道作业题,要求同学们求出\({1,2,3,4,5}\)的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x ...
- 【BZOJ-2734】集合选数 状压DP (思路题)
2734: [HNOI2012]集合选数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1070 Solved: 623[Submit][Statu ...
- bzoj 2734: [HNOI2012]集合选数 状压DP
2734: [HNOI2012]集合选数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 560 Solved: 321[Submit][Status ...
随机推荐
- 交叉熵、KL 散度 | 定义与相互关系
1 KL 散度 对于离散概率分布 \(P\) 和 \(Q\) ,KL 散度定义为: \[\text{KL}(P \| Q) = -E_{x\sim P}\log P(x)-\log Q(x) \\ = ...
- 【郝斌C ST】02
自学视频<郝斌C语言自学教程> 10: https://www.bilibili.com/video/BV1os411h77o C语言大纲 - 1.简介 - 2.基本编译知识 - 3.数据 ...
- Webots —— 好用的人形机器人仿真平台
相关: https://cyberbotics.com/doc/guide/tutorials 下载地址: https://github.com/cyberbotics/webots/releases ...
- 公共的网络云盘的存储真的安全吗?—— 百度云盘上的PDF文件无故被改名
在百度云盘上上传了一个PDF文件,内容: 本来是没有啥问题的,但是今天使用百度云盘发现这个PDF文件居然被改名,被取消掉了扩展名: 简直是离谱离了一个大谱,太可怕了,看来这种公共云盘真的不太靠谱,虽然 ...
- Linux共享内存通信的C语言Demo代码
重点注明: 本文代码来源于: https://blog.csdn.net/github_38294679/article/details/122360026 ===================== ...
- php学习笔记(一)————php类的概念
<?php //类的概念 /* * 一个类包含自己的属性和函数 * * 属性:属于类自己的常量和变量 * * 方法:就是函数 * * 类是一类事物的抽象 */ //例子: //车就是一种抽象 c ...
- 遥遥领先!鲲鹏ARM架构下国产数据同步能力大幅提升16.9倍
在上篇文章<2.6倍!WhaleTunnel客户POC实景对弈DataX>发布之后,一个客户突然向我们控诉其苦DataX久矣,因为是在信创的鲲鹏ARM CPU上运行 ,每天同步需要很长时间 ...
- CF1730G
CF1703G 链接: Problem - 1703G - Codeforces 题目大意: 你有 \(n\) 个箱子.第 \(i\) 个箱子中有 \(a_i\) 个硬币.你需要按照从箱子 \(1\) ...
- C#反射在数据库操作中的应用(反射属性,反射字段)
这几天学习反射的应用,今天把其应用到数据操作中 现记录学习笔记 环境为: 编译器:vs2017 数据库:access 反射类型为:字段 1先在类文件的定义是用哪种数据库,和用字段还是属性来反射 本例是 ...
- Webpack 核心流程
我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:霜序 三个阶段 初始化阶段 初始化参数:从配置文件.配置对 ...