codeVS 1022 覆盖

 时间限制: 1 s

 空间限制: 128000 KB

 题目等级 : 大师 Master

 题解

 题目描述 Description

 有一个N×M的单位方格中,其中有些方格是水塘,其他方格是陆地。如果要用1×2的矩阵区覆盖(覆盖过程不容许有任何部分  重叠)这个陆地,那么最多可以覆盖多少陆地面积。

 

输入描述 Input Description

输入文件的第一行是两个整数NM  (1<=NM<=100),第二行为一个整数K( K<=50),接下来的K行,每行两个整数X,Y表示K个水塘的行列位置。(1<=X<=N1<=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;
}

猜你喜欢

转载自blog.csdn.net/WX_1218639030/article/details/83306075