2020牛客暑期多校(第一场)I

1 or 2

https://ac.nowcoder.com/acm/contest/5666/I

题目描述

  Bobo has a graph with vertices and m edges where the -th edge is between the vertices and . Find out whether is possible for him to choose some of the edges such that the -th vertex is incident with exactly edges.

输入描述

  The input consists of several test cases terminated by end-of-file.
  The first line of each test case contains two integers and .
  The second line contains integers .
  The -th of the following lines contains two integers and .
  , , , . , for . The number of tests does not exceed .

输出描述

For each test case, print Yes without quotes if it is possible. Otherwise, print No without quotes.

示例1

输入

2 1
1 1
1 2
2 1
2 2
1 2
3 2
1 1 2
1 3
2 3

输出

Yes
No
Yes

分析

  首先考虑最简单的情况。如果 ,有 ,那么此题可以转化为一般图匹配问题,若最大匹配为完备匹配,则存在满足条件的方案。
  进一步考虑当 时的操作。不妨进行拆点,将点 拆成点 ,让两者各自找一个点匹配,仍然转化为一般图匹配问题。但是拆点后,由点 拆开的两个点可能正好和由点 拆开的两点相匹配,为了防止此类情况发生,应当再增加一些限制。
  我们可以将一条边 的两端分别为点 )化为两点 连边, 连边, 之间连边。若 之间匹配,那么 四点都不会与之匹配,在原图中的意义为 之间的边不是一条匹配边;反之,若 匹配, 匹配,在原图上代表 之间的边是一条匹配边。假如 要与 匹配, 要与 匹配,那么 就连了不止一条匹配边,这种情况在最大匹配中是不会出现的,因此将边化点的操作是成功的。
  建图完成后,若一般图最大匹配为完全匹配,则存在满足条件的方案。

代码

/******************************************************************
Copyright: 11D_Beyonder All Rights Reserved
Author: 11D_Beyonder
Problem ID: 2020牛客暑期多校训练营(第一场) Problem I
Date: 8/11/2020 
Description: Perfect Matching In General Graph
*******************************************************************/
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1003;
struct E
{
    int to;
    int Next=-1;
}edge[N*100];
int n,m;
int father[N];
int head[N],tot;
int color[N],pre[N],match[N],dfn[N];
int timer;
queue<int>q;
int d[N];
int deg[N];
int cnt;
inline void init();
inline void add_edge(int,int);
int father_of(int);
int lca_of(int,int);
void blossom(int,int,int);
bool bfs(int);
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        int i;
        cnt=n+2*m;
        for(i=1;i<=n;i++) 
        {
            scanf("%d",&d[i]);
            cnt+=d[i]==2;//度为2要拆点
        }
        for(i=1;i<=m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            if(d[a]==2)
            {
                add_edge(a,n*2+i);//a e
                add_edge(a+n,n*2+i);//a' e
                add_edge(2*n+i,a);//e a
                add_edge(2*n+i,a+n);//e a'
            }
            else 
            {
                add_edge(a,2*n+i);
                add_edge(2*n+i,a);
            }
            if(d[b]==2)
            {
                add_edge(b,n*2+m+i);//b e'
                add_edge(b+n,n*2+m+i);//b' e'
                add_edge(2*n+m+i,b);//e' b
                add_edge(2*n+m+i,b+n);//e' b'
            }
            else 
            {
                add_edge(b,2*n+m+i);
                add_edge(2*n+m+i,b);
            }
            add_edge(2*n+i,2*n+m+i);
            add_edge(2*n+m+i,2*n+i);
        }
        int ans=0;
        for(i=1;i<=2*(n+m);i++)
        {
            if(!match[i])
            {
                ans+=bfs(i);
            }
        }
        puts(ans==cnt>>1?"Yes":"No");
    }
    return 0;
}
inline void init()
{
    tot=0;
    timer=0;
    memset(head,-1,sizeof(head));
    memset(match,0,sizeof(match));
    memset(dfn,0,sizeof(dfn));
}
inline void add_edge(int u,int v)
{
    tot++;
    edge[tot].to=v;
    edge[tot].Next=head[u];
    head[u]=tot;
}
//=============================================
//一般图匹配模板
int father_of(int x)
{
    if(father[x]==x) return x;
    else return father[x]=father_of(father[x]);
}
int lca_of(int x,int y)
{
    timer++;
    x=father_of(x);
    y=father_of(y);
    for(;;x^=y^=x^=y)
    {
        if(x)
        {
            if(dfn[x]==timer) return x;
            dfn[x]=timer;
            x=father_of(pre[match[x]]);
        }
    }
}
void blossom(int x,int y,int lca)
{
    while(father_of(x)!=lca)
    {
        pre[x]=y;
        if(color[match[x]]==1)
        {
            color[match[x]]=0;
            q.push(match[x]);
        }
        if(father[x]==x) father[x]=lca;
        if(father[match[x]]==match[x]) father[match[x]]=lca;
        y=match[x];
        x=pre[y];
    }
}
bool bfs(int x)
{
    int i;
    for(i=1;i<=2*(n+m);i++) father[i]=i;
    memset(color,-1,sizeof(color));
    memset(pre,0,sizeof(pre));
    while(!q.empty()) q.pop();
    color[x]=0;
    q.push(x);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(i=head[u];~i;i=edge[i].Next)
        {
            int v=edge[i].to;
            if(color[v]==-1)
            {
                pre[v]=u;
                color[v]=1;
                if(!match[v])
                {
                    for(register int go=1;go;v=go,u=pre[go])
                    {
                        go=match[u];
                        match[u]=v; 
                        match[v]=u;
                    }
                    return 1;
                }
                color[match[v]]=0;
                q.push(match[v]);
            }
            else if(!color[v]&&father_of(u)!=father_of(v))
            {
                int lca=lca_of(u,v);
                blossom(u,v,lca);
                blossom(v,u,lca);
            }
        }
    }
    return 0;
}

后记

  注意初始化。

牛客暑期多校训练营题解 文章被收录于专栏

收集牛客暑期多校训练营的题解

全部评论

相关推荐

11-27 12:43
已编辑
门头沟学院 C++
点赞 评论 收藏
分享
在评审的大师兄很完美:像这种一般就是部门不匹配 转移至其他部门然后挂掉 我就是这样被挂了
点赞 评论 收藏
分享
尊尼获获:闺蜜在哪?
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务