• 图论常见结论


    图论常见结论

    二分图:

    最大匹配:二分图中一个边的集合{E}中,当任意两条边都不相交于同一个节点时,这个边集被称作一个匹配,这个集合最大时,称为一个最大匹配。

    最小点覆盖:如果选定一个点,看做选择了它连接的所有边,能涵盖所有边时且节点最少时,称为最小点覆盖。

    最大独立集:选出一些点,使得它们两两没有边连接。选择的点最多时,这个集合称作最大独立集。

    总点数=最小点覆盖+最大独立集证明

    最小点覆盖=最大匹配( König定理)。从右边未匹配的点出发,沿着未匹配-匹配-未匹配去dfs。最终最小点覆盖就是左边出现的点和右边未出现的点。

    最小边覆盖=点数-最大匹配。

    无向图:

    最大独立集=补图的最大团,反之亦然。

    例题:传送门

    分析,首先要考虑连续的1是没用的,其次,两个1之间的这些条件没办法同时满足。如果建模成图论,往两个点之间连边,要选出一个独立集出来。借用上面的结论,那就是求一个补图的最大团。

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 45;
    
    int nd, nm, G[N][N];
    int cntClique, pts[N], res[N], cnt[N];
    
    map<string, int> H;
    
    int n;
    
    vector<int> v;
    
    bool dfs(int pos, int num){
        for(int i=pos+1;i<=n;++i){
            if(cnt[i]+num<=cntClique)return false;//这里是一处剪枝
    
            if(G[pos][i]){//考虑与当前团节点的关系
                int ok=1;
                for(int id=1;id<=num;++id){
                    if(!G[i][pts[id]]){
                        ok=0;break;
                    }
                }
    
                if(ok){
                    pts[num+1]=i;
                    if(dfs(i,num+1))return true;
                }
            }
        }
    
        if(num>cntClique){ //多枚举一个,最多只扩充一个点
            for(int i=1;i<=num;++i){
                res[i]=pts[i];
            }
            cntClique=num;
            return true;
        }
    
        return false;
    }
    
    void maxClique(){
        cntClique=-1;
        for(int i=n;i>0;--i){
            pts[1]=i;
            dfs(i,1);
            cnt[i]=cntClique;
        }
    }
    
    int main(){
        ios_base::sync_with_stdio(0);
        cin.tie(0);
    
        memset(G,1,sizeof G);
    
        cin>>nd>>nm;
        for(int i=1;i<=nd;++i){
            int op;string s;
            cin>>op;
            if(op==1){
                v.clear();
            }else{
                cin>>s;
                if(!H.count(s)){
                    H[s]=++n;
                }
                /*n^2建图跑的飞起,cf数据有问题*/
                int y=H[s];
                for(auto& x:v){
                    G[x][y]=0;
                    G[y][x]=0;
                }
                v.push_back(y);
            }
        }
    
        maxClique();
        if(cntClique<0){
            cout<<"0";
        }else{
            cout<<cntClique;
        }
        return 0;
    }
    
    
  • 相关阅读:
    windows下设置sublime
    sublime编辑器快捷键
    Navicat Premium 12.1.8.0安装与激活
    Win查找弹窗广告来源
    canvas-绘制时钟
    H5标签-canvas实现颜色拾取功能
    第一次Sprint团队贡献分
    Sprint第一个冲刺(第十一天)
    Sprint第一个冲刺(第十天)
    Sprint第一个冲刺(第九天)
  • 原文地址:https://www.cnblogs.com/JohnRan/p/13576881.html
Copyright © 2020-2023  润新知