• 二分图


    二分图的判定:

    二分图: 让很多点分别放在2 端 ,每一个端内的点不能够相连接 , 2端的点可以任意连接。

    染色:

     小注意: 每一个点没有去过,就去,不要dfs(1) 就走了

    color[1]=1;
    bool dfs(int u)
    {
        for(ri i=head[u];i;i=bian[i].net)
        {
            int v=bian[i].to;
            if(color[v]&&color[v]!=color[u]) continue;
            if(color[v]&&color[v]==color[u]) return 0;
            if(!color[v])
            {
                color[v]=3-color[u];
                if(!dfs(v)) return 0;
            }
        }
        return 1;
    }
    View Code

    二分图的最大匹配:

    bool dfs(int u)
    {    
       
        for(int j=son[u];j;j=bian[j].net)
        {   
           int v=bian[j].val;
           if(vis[v]) continue ;
             vis[v]=1;
          if(pipei[v]==-1||dfs(pipei[v]))
          {
            pipei[u]=a;
            return true;
            }
        }
       return false;
    }
    
        for(i=1;i<=n;i++)
        {
            if(pipei[i]==-1)
            {   
                memset(vis,0,sizeof vis);
                ans=ans+dfs(i);
            }
        }
    View Code

    小定理: 出去最大匹配的点后,剩下的点一定不会相连接。

    相关定理: 转载:罗茜

    最小顶点覆盖:在二分图中寻找一个尽量小的点集,使图中每一条边至少有一个点在该点集中。

      最小顶点覆盖 == 最大匹配。

      反证法证明:假设当前存在一条两个端点都不在最小顶点覆盖点集中,那么这么光芒四射的边定可以增大最大匹配边集,与最大匹配矛盾,所以得证。

     

    最小路径覆盖:在二分图中寻找一个尽量小的边集,使图中每一个点都是该边集中某条边的端点。

      最小路径覆盖 == 顶点数 - 最大匹配。

      证明:因为一条边最多可以包含两个顶点,所以我们选边的时候让这样的边尽量多,也就是说最大匹配的边集数目咯。剩下的点就只能一个边连上一个点到集合里啦。

     

    最大独立集:在N个点中选出来一个最大点集,使这个点集中的任意两点之间都没有边。

      最大独立集 == 顶点数 - 最大匹配。

      证明:因为去掉最大匹配两端的顶点去掉以后,剩下的点肯定是独立集。我们再从每个匹配里面挑选出来一个点加入到独立集中,也是不会破坏原有独立集的独立性的。

    一些题目的联系:
       题目: 下面2道题 建边很关键

    问题 D: 【高级算法】火力网
    时间限制: 1 Sec  内存限制: 128 MB
    提交: 13  解决: 11
    [提交] [状态] [讨论版] [命题人:外部导入]
    题目描述
    给出一个N*N的网格,用'.'表示空地,用'X'表示墙。在网格上放碉堡,可以控制所在的行和列,但不能穿过墙。
    问:最多能放多少个碉堡?
    例如,下图最多可放5个碉堡(黑色圆点)
    
    输入
    第1行:一个整数N(N<=20)
    接下来N行,每行N个字符
    输出
    第1行:1个整数,表示最多可放碉堡数。
    样例输入 Copy
    4
    .X..
    ....
    XX..
    ....
    样例输出    Copy
    5
    View Code

        代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int M = 10005;
    const int N = 10005;
    #define ri register int
    bool mp[1010][1010];
    int n,m,f[1010][1010];
    int vis[N],pipei[N];
    vector <int> q[10010];
     
    void init()
    {
        int cent=1;
        for(ri j=1;j<=n;j++)
        {
           for(ri i=1;i<=n;i++)
           {
            if(!mp[i][j]) f[i][j]=cent;
            else if(!mp[i-1][j]) cent++;
            }
            cent++; 
        }
        m=cent,cent++;
        for(ri i=1;i<=n;i++)
        {
            for(ri j=1;j<=n;j++)
            {
                if(!mp[i][j]) q[f[i][j]].push_back(cent);
                else if(!mp[i][j-1]) cent++;
            }
            cent++;
        }
    }
    bool dfs1(int u)
    {
        for(ri i=0;i<q[u].size();i++)
        {
            int v=q[u][i];
            if(vis[v]) continue;
              vis[v]=1;
            if(!pipei[v]||dfs1(pipei[v]))
            {
                pipei[v]=u;
                return 1;
            }
        }
        return 0;
    }
    void getans()
    {
        int ans=0;
        for(ri i=1;i<=m;i++)
        {
            memset(vis,0,sizeof vis);
            if(!pipei[i])
            ans+=dfs1(i);
        }
        printf("%d
    ",ans);
    }
    int main(){
        scanf("%d
    ",&n);
        for(ri i=1;i<=n;i++)
        for(ri j=1;j<=n;j++)
        {
            char c;
            cin>>c;
            if(c=='X')
            mp[i][j]=1;
        }
        init();
        getans();
    }
    View Code

     题目:

    问题 C: [Balic2001]棋盘上的骑士
    时间限制: 2 Sec  内存限制: 64 MB
    提交: 8  解决: 5
    [提交] [状态] [讨论版] [命题人:外部导入]
    题目描述
    一个N*N的棋盘上,有一些小方格被拿走了,不能放置骑士,其它位置可以放。现要在棋盘上放若干骑士,要求任一个骑士都不能在其他骑士的攻击点上。请算出棋盘上最多能有几个骑士。骑士攻击范围如图所示(S是骑士的位置,X表示马的攻击点)  
    输入
    第一行包含2个整数n和m,用单个的空格分开,1<=n<=200 , 0<=m < 40000;n 是国际象棋棋盘的大小,m是被拿走的格子数。 下面m行每行包含 2 个整数:x和y,用单个的空格分开,1<=x,y<=n,这些是被拿走的格子的坐标。 棋盘的左上角的坐标是(1,1),右下角是(n,n)。拿走的格子没有重复的。
    输出
    一个整数,它应该是能放在国际象棋棋盘上的互不攻击对方的马的最大的数量。
    样例输入 Copy
    3 2
    1 1
    3 3
    样例输出    Copy
    5
    View Code

     代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int N  = 10005;
    const int M  = 20002;
    #define ri register int
    int m,n;
    bool mp[1010][1010];
    int g[1010][1010],xq[M],yq[M],link[M],vis[M];
    int X[20]={2,1,-1,-2,-2,-1,1,2};
    int Y[20]={1,2,2,1,-1,-2,-2,-1};
    bool check(int x,int y)
    {
        if(x<1||y<1||y>n||x>n||mp[x][y])
         return 0;
         return 1;
    }
    bool dfs(int u)
    {
        int x=xq[u];
        int y=yq[u];
        int jishu1=7;
        while(jishu1>=0)
        {
          int xx=x+X[jishu1];
          int yy=y+Y[jishu1--];
          if(!check(xx,yy)) continue;
          int trmp=g[xx][yy];
           if(vis[trmp]) continue;
           vis[trmp]=1;
           if(!link[trmp]||dfs(link[trmp]))
           {
             link[trmp]=u;
             return 1;
           }
        }
        return 0;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(ri i=1;i<=m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            mp[a][b]=1;
         }
         int one=0,two=0;
        for(ri i=1;i<=n;i++)
        for(ri j=1;j<=n;j++)
        {
            if(mp[i][j]) continue;
            if(!((i+j)&1))
            {
                g[i][j]=++two;
            }
            else
            {
                xq[++one]=i;
                yq[one]=j;
            }
        }
        int ans=n*n-m;
        for(ri i=1;i<=one;i++)
        {
            memset(vis,0,sizeof vis);
            if(dfs(i)) ans--;
        }
        printf("%d
    ",ans);
    }
    View Code

     题目:二分图+floyed(为什么不能加匹配呢)

    1995: 【NOIP模拟赛】捉迷藏
    时间限制: 1 Sec  内存限制: 128 MB
    提交: 9  解决: 3
    [提交] [状态] [讨论版] [命题人:外部导入]
    题目描述
    vani和cl2在一片树林里捉迷藏…… 
    这片树林里有N座房子,M条有向道路,组成了一张有向无环图。
    树林里的树非常茂密,足以遮挡视线,但是沿着道路望去,却是视野开阔。如果从房子A沿着路走下去能够到达B,那么在A和B里的人是能够相互望见的。
    现在cl2要在这N座房子里选择K座作为藏身点,同时vani也专挑cl2作为藏身点的房子进去寻找,为了避免被vani看见,cl2要求这K个藏身点的任意两个之间都没有路径相连。
    为了让vani更难找到自己,cl2想知道最多能选出多少个藏身点? 
    输入
    第一行两个整数N,M。
    接下来M行每行两个整数x、y,表示一条从x到y的有向道路。 
    输出
    一个整数K,表示最多能选取的藏身点个数。 
    样例输入 Copy
    4 4
    1 2
    3 2
    3 4
    4 2
    样例输出    Copy
    2
    提示
    对于20% 的数据,N≤10,M<=20。
    对于60% 的数据, N≤100,M<=1000。
    对于100% 的数据,N≤200,M<=300001<=x,y<=N。 
    View Code

     代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int M = 30050;
    const int N = 10005;
    #define ri register int
    int n,m,vis[N],pipei[N];
    bool mp[1010][1010];
    bool dfs1(int u)
    {
        for(ri i=1;i<=n;i++)
        {
        if(!vis[i]&&mp[u][i])
        {
            vis[i]=1;
            if(!pipei[i]||dfs1(pipei[i]))
            {
                pipei[i]=u;
                return 1;
            }
        }
        }
        return 0;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(ri i=1;i<=m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            mp[a][b]=1;
        }
        for(ri k=1;k<=n;k++)
        for(ri i=1;i<=n;i++)
        for(ri j=1;j<=n;j++)
        {
            if(k==i||i==j||j==k) continue;
            mp[i][j]=mp[i][j]||(mp[i][k]&&mp[k][j]);
        }
        int ans=0;
        for(ri i=1;i<=n;i++)
        {
            memset(vis,0,sizeof vis);
             
            if(dfs1(i)) ans++;
        }
        printf("%d
    ",n-ans);
        return 0;
    }
    View Code

    二分图的带权的最大匹配 KM 算法 时间复杂度 n^4   

    pip 要初始化为-1;

    #include <bits/stdc++.h>
    using namespace std;
    #define ri register int 
    #define M 505
    
    
    int n,m;
    struct edge{
        int d,val;
        edge(){}
        edge (int a,int b){d=a,val=b;}
    };
    vector <edge> p[M];
    
    int vx[M],vy[M];
    int vist[M];
    int pip[M];
    
    int xx;
    
    stack <int> q1;
    stack <int> q2;
    
    bool dfs(int a)
    {
        for(ri i=0;i<p[a].size();i++)
        {
            int b=p[a][i].d;
            if(vist[b]) continue;
            vist[b]=1;
            int t=vx[a]+vy[b];
        
            if(t==p[a][i].val)       // 这个顺序很重要 
            {
                if(pip[b]==-1||dfs(pip[b]))
                {
                    pip[b]=a;
                    q1.push(a);
                    q2.push(b);
                    
                    return true;
                }
            }else
            xx=min(vx[a]-vy[b]-p[a][i].val,xx);
            
        }
        return false;
        
    }
    
    int main(){
        
        memset(pip,-1,sizeof(pip)); //// remember  
        scanf("%d%d",&n,&m);
        for(ri i=1;i<=m;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            edge d;d=edge(b,c);
            p[a].push_back(d);
        }
        for(ri i=1;i<=n;i++)
        {
            int trmp = -19980739;
            
            for(ri j=0;j<p[i].size();j++)
            {
                trmp=max(trmp,p[i][j].val);
            }
            vx[i]=trmp;
        }
        
        for(ri i=1;i<=n;i++)
        {
            memset(vist,0,sizeof(vist));
            xx=19980739;
            
            while(!dfs(i))
            {
                memset(vist,0,sizeof(vist));
                while(!q1.empty())
                {
                    int a=q1.top();
                    q1.pop();
                    vx[a]-=xx;
                }
                while(!q2.empty())
                {
                    int a=q2.top();
                    q2.pop();
                    vy[a]+=xx;
                }
                xx=19980739;
            }
        }
        long long ans=0;
        
        for(ri i=1;i<=n;i++)
        {
            ans+=vx[i];
            ans+=vy[i];
        }
        printf("%lld
    ",ans);
        
        for(ri i=1;i<=n;i++)
        printf("%d ",pip[i]);
        
        return 0;
        
    } 
    View Code
  • 相关阅读:
    bzoj 1217: [HNOI2003]消防局的设立
    [USACO09FEB]庙会班车Fair Shuttle
    bzoj 1052: [HAOI2007]覆盖问题
    bzoj 1974: [Sdoi2010]代码拍卖会
    bzoj 1835: [ZJOI2010]基站选址
    bzoj 1875: [SDOI2009]HH去散步
    bzoj 3295: [Cqoi2011]动态逆序对
    bzoj 2120: 数颜色
    P1032 字串变换
    简析拓扑排序
  • 原文地址:https://www.cnblogs.com/Lamboofhome/p/11814122.html
Copyright © 2020-2023  润新知