用最大流是个假算法(网络流题解:https://blog.csdn.net/qq_43497140/article/details/107302444#comments_12808405),虽然牛客没有重测,我还是来补一发带花树正解(csdn: https://blog.csdn.net/qq_43497140/article/details/107387903

    首先建图是这样的:

    每个条边拆成两个点x,y,x和y连边

    这条边连的两个点u,v,u拆成d[u]个点,分别和x连边,v拆成d[v]个点,分别和y连边

    然后如果是完全匹配,就输出yes

    解释一下为什么完全匹配就能yes

    如果是完全匹配,每个点都被匹配上了,这样就达到了题目要求的每个点必须连di条边的要求,但是,这是否能保证一条边上两个点,如果一点和该边相连,另一点也同时相连的效果呢?

    当然是可以的,比如对于建图部分所说的点v,他如果匹配到了x,那么要达到完全匹配,y已经不能和x匹配,那必和v(或它拆出来的点)匹配,这样就达到了边上每个点必定同时匹配这条边的效果

 链接:https://ac.nowcoder.com/acm/contest/5666/I
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述

Bobo has a graph with n vertices and m edges where the i-th edge is between the vertices aia_iai and bib_ibi. Find out whether is possible for him to choose some of the edges such that the i-th vertex is incident with exactly did_idi edges.
输入描述:

The input consists of several test cases terminated by end-of-file.

The first line of each test case contains two integers n and m.
The second line contains n integers d1,d2,…,dnd_1, d_2, \dots, d_nd1,d2,…,dn.
The i-th of the following m lines contains two integers aia_iai and bib_ibi.

* 1≤n≤501 \leq n \leq 501≤n≤50
* 1≤m≤1001 \leq m \leq 1001≤m≤100

* 1≤di≤21 \leq d_i \leq 21≤di≤2

* 1≤ai,bi≤n1 \leq a_i, b_i \leq n1≤ai,bi≤n

* ai≠bia_i \neq b_iai=bi
* {ai,bi}≠{aj,bj}\{a_i, b_i\} \neq \{a_j, b_j\}{ai,bi}={aj,bj} for i≠ji \neq ji=j
* The number of tests does not exceed 100.
输出描述:

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

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

输出

复制Yes No Yes

Yes
No
Yes
#include<bits/stdc++.h>
#pragma GCC optimize(3)
using namespace std;
#include<bits/stdc++.h>
using namespace std;
#define I inline int
#define V inline void
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define REP(u) for(int i=h[u],v;v=e[i].t,i;i=e[i].n)
const int N=1e3+1,M=1e5+1;
queue<int>q;
int n,m,tot,qwq,ans;
int h[N],lk[N],tag[N],fa[N],pre[N],dfn[N];
struct edge{int t,n;}e[M];
V link(int x,int y){lk[x]=y,lk[y]=x;}
V add_edge(int x,int y){
	if(!lk[x]&&!lk[y])link(x,y),ans++;
	e[++tot]=(edge){y,h[x]},h[x]=tot;
	e[++tot]=(edge){x,h[y]},h[y]=tot;
}
V rev(int x){if(x)rev(x[pre][lk]),link(x,pre[x]);}
I find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
I lca(int x,int y){
	for(qwq++;;x=x[lk][pre],swap(x,y))
		if(dfn[x=find(x)]==qwq)return x;
		else if(x)dfn[x]=qwq;
}
V shrink(int x,int y,int p){
	for(;find(x)!=p;x=pre[y]){
		pre[x]=y,y=lk[x],fa[x]=fa[y]=p;
		if(tag[y]==2)tag[y]=1,q.push(y);
	}
}
I blossom(int u){
	FOR(i,1,n)tag[i]=pre[i]=0,fa[i]=i;
	tag[u]=1,q=queue<int>(),q.push(u);
	for(int p;!q.empty();q.pop())REP(u=q.front())
		if(tag[v]==1)
			p=lca(u,v),shrink(u,v,p),shrink(v,u,p);
		else if(!tag[v]){
			pre[v]=u,tag[v]=2;
			if(!lk[v])return rev(v),1;
			else tag[lk[v]]=1,q.push(lk[v]);
		}
	return 0;
}
vector<int>a[N];
int d[N];
void init()
{
    for(int i=1;i<=N-10;i++) a[i].clear();
    ans=tot=qwq=0;
    memset(h,0,sizeof(h));
    memset(fa,0,sizeof(fa));
    memset(pre,0,sizeof(pre));
    memset(dfn,0,sizeof(dfn));
    memset(lk,0,sizeof(lk));
    memset(tag,0,sizeof(tag));
    memset(d,0,sizeof(d));
}
int main(){
	while(scanf("%d %d",&n,&m)!=EOF)
    {
        init();
 
	for(int x,y;m--;add_edge(x,y))scanf("%d%d",&x,&y);
	FOR(i,1,n)ans+=!lk[i]&&blossom(i);
	cout<<ans<<'\n';
	FOR(i,1,n)cout<<lk[i]<<' ';
    }
}