zoukankan      html  css  js  c++  java
  • 2171 棋盘覆盖

    2171 棋盘覆盖

     

     时间限制: 1 s
     空间限制: 32000 KB
     题目等级 : 黄金 Gold
     
     
     
    题目描述 Description

    给出一张n*n(n<=100)的国际象棋棋盘,其中被删除了一些点,问可以使用多少1*2的多米诺骨牌进行掩盖。

    输入描述 Input Description

    第一行为n,m(表示有m个删除的格子)
    第二行到m+1行为x,y,分别表示删除格子所在的位置
    x为第x行
    y为第y列

    输出描述 Output Description

    一个数,即最大覆盖格数

    样例输入 Sample Input

    8 0

    样例输出 Sample Output

    32

    数据范围及提示 Data Size & Hint

    经典问题

    分类标签 Tags 点此展开 

     
    暂无标签
    匈牙利
    /*其实如果把国际棋盘白色的看成集合A,黑的看成集合B。
    //每个合法的格子与相邻的合法格子有无向边(合法就是没有被删除),
    //这种最大匹配就是所谓的最大覆盖数。*/
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const int dx[]={0,0,1,-1};
    const int dy[]={1,-1,0,0};
    const int N=1e4+10;
    const int V=110;
    int n,m,num,ans,tot,mp[V][V],id[V][V],match[N],yy[N],head[N],next[N<<2],list[N<<2]; 
    void add(int x,int y){
        list[++tot]=y;
        next[tot]=head[x];
        head[x]=tot;
    }
    bool inside(int x,int y){
        return x>0&&x<=n&&y>0&&y<=n;
    }
    bool hungary(int x){
        for(int i=head[x];i;i=next[i]){
            if(!yy[list[i]]){
                yy[list[i]]=1;
                if(!match[list[i]]||hungary(match[list[i]])){
                    match[list[i]]=x;
                    return 1;
                }
            }
        }
        return 0;
    }
    void mapping(){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                id[i][j]=++num;
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1+!(i&1);j<=n;j+=2){
                if(mp[i][j]) continue;
                for(int k=0;k<4;k++){
                    int nx=i+dx[k],ny=j+dy[k];
                    if(inside(nx,ny)&&!mp[nx][ny]){
                        add(id[i][j],id[nx][ny]);
                    } 
                }
            }
        }
    }
    void solve(){
        for(int i=1;i<=n;i++){
            for(int j=1+!(i&1);j<=n;j+=2){
                if(mp[i][j]) continue; 
                memset(yy,0,sizeof yy);
                if(hungary(id[i][j])) ans++; 
            }
        }
        printf("%d",ans);
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1,x,y;i<=m;i++) scanf("%d%d",&x,&y),mp[x][y]=1;
        mapping();
        solve();
        return 0;
    }

    网络流

    /*思路:
    我们可以对棋盘进行染,黑白相间,即相临两格不同色,这样染完色,我们就可以将同种颜色的格子作为一个集合,另外一种颜色作为一个集合,然后相邻格子间存在边的关系   (当然得排除挖去的部分)。
    求二分图最大匹配*/
    #include<cstdio>
    #include<iostream>
    using namespace std;
    const int dx[]={0,0,1,-1};
    const int dy[]={1,-1,0,0};
    const int N=210;
    const int M=N*N;
    const int inf=0x3f3f3f3f;
    int n,m,S,T,num,id[N][N],mp[N][N],head[M],dis[M],q[M*5];
    struct node{
        int v,next,cap;
    }e[M*10];int tot=1;
    void add(int x,int y,int z){
        e[++tot].v=y;e[tot].cap=z;e[tot].next=head[x];head[x]=tot;
        e[++tot].v=x;e[tot].cap=0;e[tot].next=head[y];head[y]=tot;
    }
    bool bfs(){
        for(int i=S;i<=T;i++) dis[i]=inf;
        int h=0,t=1;
        q[t]=S;dis[S]=0;
        while(h!=t){
            int x=q[++h];
            for(int i=head[x];i;i=e[i].next){
                int v=e[i].v;
                if(e[i].cap&&dis[v]>dis[x]+1){
                    dis[v]=dis[x]+1;
                    if(v==T) return 1;
                    q[++t]=v;
                }
            }
        }
        return dis[T]<inf;
    }
    int dfs(int x,int f){
        if(x==T) return f;
        int used=0,t;
        for(int i=head[x];i;i=e[i].next){
            int v=e[i].v;
            if(e[i].cap&&dis[v]==dis[x]+1){
                t=dfs(v,min(f,e[i].cap));
                e[i].cap-=t;e[i^1].cap+=t;
                f-=t;used+=t;
                if(!f) return used;
            }
        }
        dis[x]=0;
        return used;
    }
    int dinic(){
        int res=0;
        while(bfs()) res+=dfs(S,inf);
        return res;
    }
    void mapping(){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                id[i][j]=++num;
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(mp[i][j]) continue;
                if((i+j)&1^1){
                    add(S,id[i][j],1);
                    for(int k=0;k<4;k++){
                        int nx=i+dx[k],ny=j+dy[k];
                        if(nx<1||nx>n||ny<1||ny>n||mp[nx][ny]) continue;
                        add(id[i][j],id[nx][ny],1);
                    }
                }
                else{
                    add(id[i][j],T,1);
                }
            }
        }
    }
    int main(){
        scanf("%d%d",&n,&m);S=0;T=n*n+1;
        for(int i=1,x,y;i<=m;i++) scanf("%d%d",&x,&y),mp[x][y]=1;
        mapping();
        printf("%d",dinic());
        return 0;
    } 
  • 相关阅读:
    【JZOJ6271】【NOIP提高组A】锻造 (forging)
    【JZOJ6272】【NOIP提高组A】整除 (division)
    【JZOJ3397】【GDOI2014模拟】雨天的尾巴
    input绑定datapicker控件后input再绑定blur或者mouseout等问题
    解决每次打开office 2010显示正在配置的问题
    Ext JS treegrid 发生的在tree上增加itemclick 与在其它列上增加actioncolumn 发生事件冲突(event conflict)的解决办法
    Ext JS4 学习笔记之发送表单(Form)时也将表单下的表格(Grid)数据一同发送的方法
    本地同时启动两个tomcat
    转: ExtJS中xtype一览
    web前端基础知识及快速入门指南
  • 原文地址:https://www.cnblogs.com/shenben/p/6259860.html
Copyright © 2011-2022 走看看