zoukankan      html  css  js  c++  java
  • 3052 多米诺[二分图匹配]

    3052 多米诺

     

     时间限制: 1 s
     空间限制: 256000 KB
     题目等级 : 钻石 Diamond
     
     
     
    题目描述 Description

    一个矩形可以划分成M*N个小正方形,其中有一些小正方形不能使用。一个多米诺骨牌占用两个相邻的小正方形。试问整个区域内最多可以不重叠地放多少个多米诺骨牌且不占用任何一个被标记为无法使用的小正方形。

    输入描述 Input Description

    第一行有两个用空格隔开的正整数M和N。

        第二行有一个正整数K,表示共有K个小正方形不能使用。输入数据保证K<=M*N。

        以下K行每行有两个用空格隔开的数X和Y,表示第X行的第Y个小正方形不能使用。

    输出描述 Output Description

    输出最多能放多少个多米诺骨牌。

    样例输入 Sample Input

    3 3

    2

    1 1

    2 2

    样例输出 Sample Output

    3

    数据范围及提示 Data Size & Hint

    对于30%的数据,M=1;

        对于50%的数据,M<=2;

        对于70%的数据,M<=3;

        对于100%的数据,M<=50,N<=50。

    分类标签 Tags 点此展开 

     
    AC代码:
    /*
      二分图匹配问题
      问题是从一坨方格关系中选出尽量多的关系,使每个方格只选一次。 
      通过观察我们可以发现,横坐标加纵坐标是偶数的方格只能和奇数的方格匹配,所以就变成了二分图的匹配问题。 
    */
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=55;
    const int M=N*N;
    int n,m,cas,ans,tot,head[M],match[M],g[N][N];
    bool vis[M];
    struct node{
        int v,next;
    }e[M*10];
    void add(int x,int y){
        e[++tot].v=y;
        e[tot].next=head[x];
        head[x]=tot;
    }
    bool hungury(int u){
        for(int i=head[u],v;i;i=e[i].next){
            v=e[i].v;
            if(!vis[v]){
                vis[v]=1;
                if(!match[v]||hungury(match[v])){
                    match[v]=u;
                    return 1;
                }
            }
        }
        return 0;
    }
    int main(){
        scanf("%d%d%d",&n,&m,&cas);
        for(int x,y;cas--;) scanf("%d%d",&x,&y),g[x][y]=1;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if((i+j&1)||g[i][j]) continue;
                if(!g[i-1][j]&&i-1>=1) add((i-1)*m+j,(i-2)*m+j);
                if(!g[i+1][j]&&i+1<=n) add((i-1)*m+j,i*m+j);
                if(!g[i][j-1]&&j-1>=1) add((i-1)*m+j,(i-1)*m+j-1);
                if(!g[i][j+1]&&j+1<=m) add((i-1)*m+j,(i-1)*m+j+1);
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if((i+j&1)||g[i][j]) continue;
                memset(vis,0,sizeof vis);
                if(hungury((i-1)*m+j)) ans++;
            }
        }
        printf("%d",ans);
        return 0;
    }
     
  • 相关阅读:
    第五周作业
    第四周作业
    第三周作业(两个题)
    第六周作业
    第五周作业
    第四周作业
    第三周作业
    第二周作业
    求最大值及其下标
    查找整数
  • 原文地址:https://www.cnblogs.com/shenben/p/6054394.html
Copyright © 2011-2022 走看看