【算法复习】codevs1022 匈牙利算法

题目描述 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

【题解】普通二分图匹配,黑白染色

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
using namespace std;
const int m1[4]={0,0,1,-1},m2[4]={1,-1,0,0};
int n,m,k,a[101][101],cnt[2],tag[101][101],c[5001][5001],all,used[5001],girl[5001];
inline bool find(int h){
    for(int i=1;i<=cnt[1];i++)
        if(c[h][i]==true&&used[i]==false){
            used[i]=true;
            if(girl[i]==0||find(girl[i])){
                girl[i]=h;
                return true;
            }
        }
    return false;
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1,x,y;i<=k;i++){
        scanf("%d%d",&x,&y);
        a[x][y]=1;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(!a[i][j]){
            cnt[(i+j)&1]++;
            tag[i][j]=cnt[(i+j)&1];
        }    
    for(int i=1;i<=n;i++)
        for(int j=1,x,y;j<=m;j++){
            if((!a[i][j])&&(i+j)%2==0){
                for(int k=0;k<4;k++){
                    x=i+m1[k];y=j+m2[k];
                    if(!(1<=x&&x<=n&&1<=y&&y<=m)) continue;
                    if(!a[x][y]){
                        c[tag[i][j]][tag[x][y]]=1;
                    }
                }    
            } 
        }
    for(int i=1;i<=cnt[0];i++){
        memset(used,false,sizeof(used));
        if(find(i)) all++;
    }
    cout<<all<<endl;
    return 0;
}

当然,比赛的时候谁会去写这玩意啊

posted @ 2016-11-18 09:18  ExiledPoet  阅读(180)  评论(0编辑  收藏  举报