\(n\times n\) 的棋盘,有一些障碍物,在没有障碍物的格子上最多放多少个国际象棋的马,使之两两不攻击?
一个和卜凡约饭的中午,突然接到春哥求助这个题.
卜凡瞟了一眼,想都没想,淡定开口:“爆搜.”
一看数据立刻傻了眼:\(200\times 200\),爆搜必定 TLE
… 场面一度十分尴尬(
饭后看手机,发现春哥补刀:有人说是最大独立集,我没搞懂.
于是立刻想明白了…然而春哥自己没有写过.
吃完晚饭突然感到手痒,于是上手写了一发,测过样例直接自信提交,70分!(太菜了吧)
前七个点 AC
了,后三个点竟然是 RE
?
想来想去没有别的地方可能 RE
了,开大边数,直接100分 AC
了.
所以,容我bb一下这道题…
题面
Description
Given a \(N\times N\) chessboard. There are \(M\) obstacles in the chessboard and the position of \(i\)-th obstacle is \((X_i,Y_i)\). You are asked to find the maximum number of knights which can be placed in the chessboard at the same time, satisfied that,
- No two knights can attack each other.
- Knights can’t be placed in obstacle.
- There can be at most one knight in a grid.
(A Knight in chess can attack 8 positions, as shown in following figure)
Input
Input is given from Standard Imput in the following format:
\(N~M\\ X_1~Y_1\\ X_2~Y_2\\ \cdots\\ X_M~Y_M\)
Output
Print the maximum number of knights.
Sample Input 1
1 | 3 2 |
Sample Output 1:
1 | 5 |
Test 1: exactly same as sample input 1
Test 2-4: \(1\leqslant N\leqslant 4\)
Test 5-6: \(1\leqslant N\leqslant 6\)
Test 7-10: \(1\leqslant N\leqslant 200\)
For all tests, \(0\leqslant M\leqslant N^2-1\), \(1\leqslant X_i\leqslant N\), \(1\leqslant Y_i\leqslant N\).
思路
一般来说棋盘上“马”的走法用横纵坐标分别来表示:
1 | const int dx[] = {1, -1, 1, -1, 2, -2, 2, -2}; |
考虑格子的纵坐标之和:马每跳一次,其奇偶性会改变. 用更“组合”的方式说,给棋盘黑白染色后,马每次跳跃的起点和终点格子颜色一定是不同的.
于是考虑按照如下方法建图:
现将所有黑格(\(x+y\) 为偶数)视为一个集合 \(X\),所有白格(\(x+y\) 为奇数)视为一个集合,则所有的跳跃都发生在 \(X,Y\) 之间,不会发生在 \(X,Y\) 各自的内部,于是这个图是一个二分图.
现在问题所求的是“最多能放多少个马”,即该图最大独立集的大小. 对于二分图,我们有
\[|最大独立集|=总点数-最大匹配数\]
所以只需求其最大匹配. 一般来说有利用匈牙利算法直接求解和利用最大流求解两种方法.
- 直接用匈牙利算法求解.
- 最大流方法:(我觉得我不应该说这么详细)
- \(X\) 左侧增加一个源点 \(S\),向 \(X\) 中每一点都连入容量为 \(1\) 的边;
- \(Y\) 右侧增加一个汇点 \(T\),\(Y\) 中每一点都向其连入容量为 \(1\) 的边;
- \(X,Y\) 之间的边容量也为 \(1\)(无穷大应该也是有道理的,毕竟源点最多出来 \(1\));
- 跑一遍最大流(比如dinic),结果即为最大匹配.
代码
第一次因为错误估计了边的数量而 RE
了后三个点,只得70分…后来实在想不到 RE
的点,就开大了很多边数,直接就 AC
了… 细想一下,确实是低估了边数.
这里简单说一下正确的边数估计:
棋盘边长是 \(N\),所以点数大约是 \(N^2\) 级别,考虑到每个点最多 \(8\) 条边,所以总边数绝不超过 \(8N^2\).
带入 \(N\leqslant 200\),边数至多是 \(8\times 200\times 200=3.2\times 10^5\). 开 maxm = 4e5
就足够了.
最后,因为这是最大流的题目,所以只用了最大流,其实匈牙利算法更短.
1 |
|