题目描述
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;
} 后记
注意初始化。

京公网安备 11010502036488号