zoukankan      html  css  js  c++  java
  • 【bzoj4808】【马】二分图最大点独立集+简单感性证明

    这里写图片描述
    (上不了p站我要死了,侵权度娘背锅)

    Description
    众所周知,马后炮是中国象棋中很厉害的一招必杀技。”马走日字”。本来,如果在要去的方向有别的棋子挡住(俗称”蹩马腿”),则不允许走过去。为了简化问题,我们不考虑这一点。马跟马显然不能在一起打起来,于是rly在一天再次借来了许多许多的马在棋盘上摆了起来……但这次,他实在没兴趣算方案数了,所以他只想知道在N×M的矩形方格中摆马使其互不吃到的情况下的最多个数。但是,有一个很不幸的消息,rly由于玩得太Happy,质量本来就不好的棋盘被rly弄坏了,不过幸好只是破了其中的一些格子(即不能再放子了),问题还是可以继续解决的。
    Input
    一行,两个正整数N和M。
    接下来N行,每行M个数,要么为0,表示没坏,要么为1,表示坏了。
    N<=200,M<=200
    Output
    一行,输出最多的个数。
    Sample Input
    2 3
    0 1 0
    0 1 0
    Sample Output
    2

    算是一道裸题了吧
    为了二分图练手以及多见一些二分图的性质

    网格图是天然的二分图(当然并不是网格图就一定是二分图的题),将网格交替染色,则发现马的走法一定是从黑到白(或从白到黑)。那么这就是求互不可达的马的数量,即 最大点独立集

    下面来感性证明一下 最大点独立集=点数-最小点覆盖(最大匹配):
    这里写图片描述
    用最少的点覆盖完了所有的边,那么如果我们删去这些属于最大匹配的点(边的一端),则剩下的点就不会和其他点相邻。如果还与别的点相邻,就说明这其实还是一个匹配,那么之前的匹配就不是最大匹配了。

    1A代码(写的好丑):

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    
    template <typename T>inline void read(T &res){
        T k=1,x=0;char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-')k=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        res=x*k;
    }
    
    const int N=205;
    
    int n,m,c[N][N];
    int head[N*N],to[N*N*8],nxt[N*N*8],hh=0;
    int tot=0,cnt=0;
    int bl[N*N];
    bool vis[N*N];
    
    void adde(int a,int b){
        hh++;
        to[hh]=b;
        nxt[hh]=head[a];
        head[a]=hh;
    }
    bool find(int u){
        for(int i=head[u];i;i=nxt[i]){
            int v=to[i];
            if(vis[v]) continue;
            vis[v]=1;
            if(bl[v]==0||find(bl[v])){
                bl[v]=u;
                return true;
            }
        }
        return false;
    }
    int main(){
        read(n),read(m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                read(c[i][j]);
                if(!c[i][j]) tot++;
            }
        for(int i=1;i<=n;i++){
            for(int j=i%2?1:2;j<=m;j+=2){
                if(c[i][j]) continue;
                if(i-2>=1&&j-1>=1&&c[i-2][j-1]==0) adde((i-1)*m+j,(i-3)*m+j-1);
                if(i-2>=1&&j+1<=m&&c[i-2][j+1]==0) adde((i-1)*m+j,(i-3)*m+j+1);
                if(i-1>=1&&j-2>=1&&c[i-1][j-2]==0) adde((i-1)*m+j,(i-2)*m+j-2);
                if(i-1>=1&&j+2<=m&&c[i-1][j+2]==0) adde((i-1)*m+j,(i-2)*m+j+2);
                if(i+2<=n&&j-1>=1&&c[i+2][j-1]==0) adde((i-1)*m+j,(i+1)*m+j-1);
                if(i+2<=n&&j+1<=m&&c[i+2][j+1]==0) adde((i-1)*m+j,(i+1)*m+j+1);
                if(i+1<=n&&j-2>=1&&c[i+1][j-2]==0) adde((i-1)*m+j,i*m+j-2);
                if(i+1<=n&&j+2<=m&&c[i+1][j+2]==0) adde((i-1)*m+j,i*m+j+2);
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=i%2?1:2;j<=m;j+=2){
                memset(vis,0,sizeof(vis));
                if(find((i-1)*m+j)) cnt++;
            }
        }
        printf("%d
    ",tot-cnt);
        return 0;
    }
  • 相关阅读:
    jQuery 源码解析(二十四) DOM操作模块 包裹元素 详解
    jQuery 源码解析(二十三) DOM操作模块 替换元素 详解
    jQuery 源码解析(二十二) DOM操作模块 复制元素 详解
    jQuery 源码分析(二十一) DOM操作模块 删除元素 详解
    jQuery 源码分析(二十) DOM操作模块 插入元素 详解
    jQuery 源码分析(十九) DOM遍历模块详解
    python 简单工厂模式
    python 爬虫-协程 采集博客园
    vue 自定义image组件
    微信小程序 image组件坑
  • 原文地址:https://www.cnblogs.com/LinnBlanc/p/7763089.html
Copyright © 2011-2022 走看看