codevs1022 覆盖[Hungary 二分图最大匹配]
codevs1022 覆盖
有一个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
相邻的可以组成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; }
Copyright:http://www.cnblogs.com/candy99/