时间限制: 1 s
空间限制: 128000 KB
题目等级 : 大师 Master
题解
题目描述 Description
有一个N×M的单位方格中,其中有些方格是水塘,其他方格是陆地。如果要用1×2的矩阵区覆盖(覆盖过程不容许有任何部分 重叠)这个陆地,那么最多可以覆盖多少陆地面积。
输入描述 Input Description
输入文件的第一行是两个整数N,M (1<=N,M<=100),第二行为一个整数K( K<=50),接下来的K行,每行两个整数X,Y表示K个水塘的行列位置。(1<=X<=N,1<=Y<=M)。
输出描述 Output Description
输出所覆盖的最大面积块(1×2面积算一块)。
样例输入 Sample Input
4 4
6
1 1
1 4
2 2
4 1
4 2
4 4
样例输出 Sample Output
4
代码中元素位置的表示方法不是通过横纵坐标
而是表格中的顺序表示法
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
struct node{
//to 代表元素 next记录下一个位置的节点
int to,next;
}e[50000009];
//ihead:邻接表的头
//cnt:邻接表大小
//mc:表示每个点所匹配到的另一个点match
//vis:Y集元素是否被访问过
int ihead[5000009],mc[5000009],cnt = 0;
bool vis[5000009];
void add(int x,int y){
++cnt;//
e[cnt].next = ihead[x];//next = 没插入之前的邻接表的头
e[cnt].to = y;//记录该点的值
ihead[x] = cnt;//修改邻接点的头
}
//匈牙利算法
//x:x集上的点,从当前点出发找增广路
//返回值:若找到增广路则返回true,否则返回false
bool dfs(int x){
for(int i = ihead[x];i != 0; i = e[i].next){
int y = e[i].to;
if(!vis[y]){//如果找到一个Y集上的点没有标记
vis[y] = true;//标记该点
//如果y是没有匹配点的,说明找到了一条增广路;或者说递归查找y的匹配点,得到了一条增广路
if(mc[y] == 0 || dfs(mc[y])){
//找到了增广路,更新mc数组
mc[x] = y;
mc[y] = x;
return true;
}
}
}
return false;
}
int getAnswer(int N,int M,vector<int> q){
for(int i = 0;i < N * M;i++){
ihead[i] = 0;
mc[i] = 0;
}
//判断符合点i能够与周围的点满足1 X 2的点都加入到邻接表当中
//可构成的点设为i + 1 <--------> i + M * N + 1
for(int i = 0;i < N * M;i++){
//点i与上面点 但 i不在第一行
if(q[i] == 0 && q[i - M] == 0 && i >= M)
add(i + 1,i - M + 1 + N * M + 1);
//点i与下面点 但是i不在最后一行
if(q[i] == 0 && q[i + M] == 0 && i + M < M * N)
add(i + 1,i + M + 1 + N * M + 1);
//点i与右面点 但是i不是最后一列
if(q[i] == 0 && q[i + 1] == 0 && (i + 1) % M != 0)
add(i + 1,i + 2 + N * M + 1);
//点i与左面点 但是i不是最前列
if(q[i] == 0 && q[i - 1] == 0 && i % M != 0)
add(i + 1,i + N * M + 1);
}
int ans = 0;
for(int i = 1; i <= N * M; ++i)
//当mc[i] = 0时
if(!mc[i]){
//如果x集中的第i个点没有匹配到Y集上的点,则从这个点出发寻找增广路
memset(vis, 0, sizeof(bool) * (N * M * 2 + 1));
//将数组置为0
if(dfs(i))
++ans;//如果找到,答案直接+1
}
return ans / 2;
}
int main(int argc, char const *argv[]) {
vector<int> q;
//N 行 M列
int N,M;
scanf("%d%d",&N,&M);
for(int i = 0;i < N * M;i++){
q.push_back(0);
}
int ni;
scanf("%d",&ni);
for(int i = 0;i < ni;i++){
//j1表示点所在的行
//j2表示点所在的列
int j1,j2;
scanf("%d%d",&j1,&j2);
//直接用元素标号记录位置
q[(j1 - 1) * M + j2 - 1] = 1;
}
printf("%d",getAnswer(N,M,q));
return 0;
}