二分图

判定

  • 一张图是二分图,当且仅当图中不存在奇环。
  • 如果两个集合中的点分别染成黑色和白色,可以发现二分图中的每一条边都一定是连接一个黑色点和一个白色点。

例题:关押罪犯

#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#define cs const
#define mid (l+r>>1)
#define il inline
#define ri register
#define pc(i) putchar(i)
using namespace std;
cs int N=2e4+3,M=1e5+3,inf=0x3f3f3f3f;
int head[N],n,m,tot,l=1,r,color[N];
struct node{int to,nxt,w;}edge[M<<1];
il void read(int &as)
{
    int f=1;char ch=getchar();as=0;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') as=(as<<3)+(as<<1)+(ch^48),ch=getchar();as*=f;
}
il void wt(int x){if(x<0) x=-x,pc('-');if(x>9) wt(x/10);pc(x%10|48);}
il void add(cs int u,cs int v,cs int w){edge[++tot]=(node){v,head[u],w},head[u]=tot;}
il bool bfs(cs int x)//验证是否可以构成二分图
{
    queue<int>q;
    for(ri int i(1);i<=n;++i) color[i]=0;
    for(ri int o(1);o<=n;++o)
    {
        if(color[o]) continue;
        q.push(o),color[o]=1;
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(ri int i(head[u]);i;i=edge[i].nxt)
                if(edge[i].w>=x)
                    if(!color[edge[i].to]) 
                        q.push(edge[i].to),color[edge[i].to]=-color[u];
                    else if(color[edge[i].to]==color[u]) return false;
        }
    }
    return true;
}
int main()
{
    read(n),read(m);
    if(m==1) return puts("0"),0;//特判只有一个人的情况,此时没有怨气值
    for(ri int i(1),u,v,w;i<=m;++i)
        read(u),read(v),read(w),r=r>w?r:w,add(u,v,w),add(v,u,w);
    r++;
    while(r>l+1)//二分答案
        if(bfs(mid)) r=mid; else l=mid;
    wt(l);
    return 0;
}

二分图匹配

  • 图的一组匹配:任意两条边都没有公共端点。
  • 最大匹配:二分图的一组匹配s是最大匹配,当且仅当图中不存在s的增广路
  • 交替路:从一个未匹配点出发,依次经过非匹配边、匹配边。
  • 增广路:从一个未匹配点出发,走交替路,若途经除出发点之外的未匹配点,则为增广路。
  • 增广路中 非匹配边=匹配边+1。

匈牙利算法(增广路算法)

#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#define cs const
#define mid (l+r>>1)
#define il inline
#define ri register
#define pc(i) putchar(i)
using namespace std;
cs int N=1003,inf=0x3f3f3f3f;
bool vis[N];
int head[N],n,m,e,tot,match[N],ans;
struct node{int to,nxt;}edge[50003];//here
il void read(int &as)
{
    int f=1;char ch=getchar();as=0;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') as=(as<<3)+(as<<1)+(ch^48),ch=getchar();as*=f;
}
il void wt(int x){if(x<0) x=-x,pc('-');if(x>9) wt(x/10);pc(x%10|48);}
il void add(cs int u,cs int v){edge[++tot]=(node){v,head[u]},head[u]=tot;}
bool dfs(cs int x)
{
    for(ri int i(head[x]),to;i;i=edge[i].nxt)
        if(!vis[to=edge[i].to])
        {
            vis[to]=1;
            /*若右y可以与左x匹配,则y为非匹配点,(x,y)为非匹配边
       或y已经与x'匹配,而x'可以找到新的y'与之匹配*/
            if(!match[to]||dfs(match[to]))
                return match[to]=x,true;
        }
    return false;
}
int main()
{
    read(n),read(m),read(e);
    for(ri int i(1),u,v;i<=e;++i) read(u),read(v),add(u,v);
    for(ri int i(1);i<=n;++i) 
    {
        for(ri int j(1);j<=n;++j) vis[j]=0;//i,j
        if(dfs(i)) ans++;
    }
    wt(ans);
    return 0;
}

  

posted @ 2022-10-22 21:27  Bertidurlah  阅读(25)  评论(1)    收藏  举报