codevs1022 覆盖[Hungary 二分图最大匹配]

codevs1022 覆盖

有一个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


相邻的可以组成1*2建边,根据i+j奇偶分类就成了二分图,hungary求最大匹配(dinic当然也可以,本题规模没必要)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=105;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,m,k,x,y,g[N][N];
struct edge{
    int v,ne;
}e[N*N*4];
int h[N*N],cnt=0;
inline int id(int i,int j){return (i-1)*n+j;}
inline void ins(int u,int v){
    cnt++;
    e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
}
void buildGraph(){
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(!g[i][j]&&(i+j)&1){
            if(i<n&&!g[i+1][j]) ins(id(i,j),id(i+1,j));
            if(j<m&&!g[i][j+1]) ins(id(i,j),id(i,j+1));
            if(i>1&&!g[i-1][j]) ins(id(i,j),id(i-1,j));
            if(j>1&&!g[i][j-1]) ins(id(i,j),id(i,j-1));
        }
}
int le[N*N],vis[N*N];
bool find(int u){
    for(int i=h[u];i;i=e[i].ne){
        int v=e[i].v;
        if(vis[v]) continue;
        vis[v]=1;
        if(!le[v]||find(le[v])){
            le[v]=u;
            return true;
        }
    }
    return false;
}
int hungary(){
    int ans=0,nn=id(n,m);
    for(int i=1;i<=nn;i++){
        memset(vis,0,sizeof(vis));
        if(find(i)) ans++;
    }
    return ans;
}
int main(int argc, const char * argv[]) {
    n=read();m=read();k=read();
    while(k--){x=read();y=read();g[x][y]=1;}
    buildGraph();
    printf("%d",hungary());
    return 0;
}
原文地址:https://www.cnblogs.com/candy99/p/6050779.html