参考文章:https://www.luogu.com.cn/blog/Repulser/solution-p3386

POJ 2492 A Bug's Life

判断无向图是否为二分图,注意图可能不连通。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int N=1e4+10;
vector<int> g[N];
int color[N]; // 记录点的染色为0或1,初始时未染色则为-1
bool dfs(int u,int now_color) // 当前点为u,当前染色为now_color(取值0或1)
{
    color[u]=now_color;
    for(int i=0;i<g[u].size();i++) // 邻接点v
    {
        int v=g[u][i];
        if(color[v]==color[u]) // 与邻接点颜色相同
            return 0; // 不为二分图,返回0
        if(color[v]==-1&&!dfs(v,color[u]^1)) // 邻接点未染色则继续dfs递归,判断其能否染色
            return 0; // 染色失败,dfs返回本层结果为0,本层再向上返回0
    }
    return 1;
}
bool solve(int n)
{
    for(int i=1;i<=n;i++) // 可能不是连通图,所以dfs所有点
        if(color[i]==-1&&!dfs(i,0))return 0; // 若i点未被染色,则dfs
    return 1;
}
int main()
{
    ios::sync_with_stdio(false);
    int T,cas=0;cin>>T;
    while(T--)
    {
        int n,m,x,y;
        cin>>n>>m;
        for(int i=1;i<=n;i++)
            g[i].clear();
        memset(color,-1,sizeof(color));
        while(m--)
        {
            cin>>x>>y;
            g[x].push_back(y);
            g[y].push_back(x);
        }
        printf("Scenario #%d:\n",++cas);
        if(solve(n))printf("No suspicious bugs found!\n\n");
        else printf("Suspicious bugs found!\n\n");
    }
    return 0;
}

洛谷 P3386 【模板】二分图最大匹配

#include <bits/stdc++.h>
using namespace std;
const int N=1e4+10,E=5e4+10;
int cnt,head[N];
struct edge
{
    int to,next;
}e[E<<1];
void add(int x,int y)
{
    e[cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt++;
}
bool vis[N]; // vis[v]=1表示左部点尝试找配对点过程中v已被预定匹配
int match[N]; // match[v]=u表示右部点v的配对点是左部点u(初始未匹配,值为0)
bool dfs(int u) // 左部点u,dfs尝试找到它的配对点
{
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to; // 可以与u相连的右部点v
        if(vis[v])continue; // 左部点u尝试找配对点过程中v已被预定匹配
        vis[v]=1;
        if(!match[v]||dfs(match[v]))
        // 1.如果v还没匹配,直接match[v]=u让它匹配上,不再递归直接返回1
        // 2.如果v已被匹配,那么继续dfs递归,尝试能否让现在v的配对点match[v]换一个配对点,
        // 这里可能多次递归,一直到最后一个点看它能否匹配上,再向上返回0或1
        {
            match[v]=u;
            return 1; // 匹配成功
        }
    } 
    return 0; // 以上尝试均失败,返回0
}
int main()
{
    ios::sync_with_stdio(false);
    memset(head,-1,sizeof(head));
    int n,m,e,x,y;
    cin>>n>>m>>e;
    while(e--)
    {
        cin>>x>>y;
        add(x,y); // 只需单向边,因为之后只遍历右部向左部连的边
    }
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof(vis)); // 注意每个左部点匹配之前都要清除上次右部点被预定的标记
        if(dfs(i))sum++; 
    }
    printf("%d\n",sum);
    return 0;
}