给你一个 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 或 二分图最大独立子集)的更多相关文章

  1. HDU 1565 - 方格取数(1) - [状压DP][网络流 - 最大点权独立集和最小点权覆盖集]

    题目链接:https://cn.vjudge.net/problem/HDU-1565 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32 ...

  2. 【BZOJ5010】【FJOI2017】矩阵填数 [状压DP]

    矩阵填数 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 给定一个 h*w 的矩阵,矩阵的行 ...

  3. BZOJ 2734 [HNOI2012]集合选数 (状压DP、时间复杂度分析)

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2734 题解 嗯早就想写的题,昨天因为某些不可告人的原因(大雾)把这题写了,今天再来写题解 ...

  4. 洛谷$P3226\ [HNOI2012]$集合选数 状压$dp$

    正解:$dp$ 解题报告: 传送门$QwQ$ 考虑列一个横坐标为比值为2的等比数列,纵坐标为比值为3的等比数列的表格.发现每个数要选就等价于它的上下左右不能选. 于是就是个状压$dp$板子了$QwQ$ ...

  5. $HNOI2012\ $ 集合选数 状压$dp$

    \(Des\) 求对于正整数\(n\leq 1e5\),{\(1,2,3,...,n\)}的满足约束条件:"若\(x\)在该子集中,则\(2x\)和\(3x\)不在该子集中."的子 ...

  6. HDU 1565 方格取数 状压dp

    题目: 给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大. Input 包括多 ...

  7. 【BZOJ-2732】集合选数 状压DP (思路题)

    2734: [HNOI2012]集合选数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1070  Solved: 623[Submit][Statu ...

  8. [HNOI2012]集合选数 --- 状压DP

    [HNOI2012]集合选数 题目描述 <集合论与图论>这门课程有一道作业题,要求同学们求出\({1,2,3,4,5}\)的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x ...

  9. 【BZOJ-2734】集合选数 状压DP (思路题)

    2734: [HNOI2012]集合选数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1070  Solved: 623[Submit][Statu ...

  10. bzoj 2734: [HNOI2012]集合选数 状压DP

    2734: [HNOI2012]集合选数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 560  Solved: 321[Submit][Status ...

随机推荐

  1. AppiumDesktop控制手机和安卓模拟器

    前言: 本期内容 如何用AppiumDesktop连接安卓手机和安卓模拟器 AppiumDesktop基本参数的获取方法,及如何驱动安卓设备 AppiumDesktop在模拟登陆和爬虫中用到的基本功能 ...

  2. holiday week2

    本周进度总结: 本周完成了小学期内容 LOL打了近20把,rank几乎不变 平均每天用6h+在编程学习上,更进一步了解了C++,我相信我有更进一步的编程水平,可以编写更多的东西 JAVA还没开始学 别 ...

  3. Fiddler使用界面介绍-左侧会话面板

    左侧会话面板,是Fiddler抓取的请求数据展示

  4. 【Java】在线文件预览服务 KkFileView

    原来有第三方在线预览服务接口: 需要收费使用: https://view.xdocin.com/ 但是经费不足,突然撤掉服务接口,只能把KkFileView架出来使用了 KkFileView官网地址: ...

  5. 【Maxwell】03 定向监听&全量输出

    一.定向监听 定向监听,即只监听某一个特定的表,或者库 1.创建样本案例 -- 创建监听的库(演示样本) CREATE DATABASE `test-db-2` CHARACTER SET 'utf8 ...

  6. 【VMware】虚拟机 VMware WorkStation Pro 下载安装(Windows)

    官网地址: 下载地址:[VMware WorkStation Pro 15.5 For Windows] https://www.vmware.com/cn/products/workstation- ...

  7. blender建模渲染Tips

    blender渲染 灯光的三种方式 1,常规灯光:shift+A选择灯光. 2,世界环境光:右侧地球图标调整. 3,物体自发光:把渲染物体变成一个发光体来进行调节灯光. 渲染视窗的调节 ctrl+b裁 ...

  8. OneFlow计算框架的OneAgent是不是一个子虚乌有的东西?

    自己是搞强化学习的,今天看了些OneFlow计算框架的一些资料,发现OneFlow官方一直有宣传自己的强化学习框架--OneAgent,但是十分诡异的是从了OneFlow的官方宣传可以看到这个词,但是 ...

  9. 【转载】 tmux 向上向下翻页,翻屏

    作者:江河湖海洋链接:https://www.jianshu.com/p/8835f2d4245f来源:简书著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. =========== ...

  10. k8s资源预留

    Kubernetes 的节点可以按照 Capacity 调度.默认情况下 pod 能够使用节点全部可用容量. 这是个问题,因为节点自己通常运行了不少驱动 OS 和 Kubernetes 的系统守护进程 ...