I 1 or 2 2020牛客暑期多校第一场

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

hdu3551改版,其实是一样的,从牛逼网友那里学了一手, 据说是claris的带花树板子

一条边会让两个点的度数-1,那么我们就是要去掉一些边,使得每个点去掉du[i]-d[i]个度数

那么就把每个点拆成du[i]-d[i]个,然后对每条边拆成两个点e,e', u的每个点连e,v的每个点连e',然后跑一般图最大匹配也就是带花树算法,如果完美匹配则为有解

解释一下为什么,如果我们不链接e-e'的话,那么对其实就是每个点拆成的点连上很多边的某一个端点,每一个点和他连的边化作的点的连通块就是一个二分图,搞二分图最大匹配,答案就是拆成的点的个数,因为我们已经满足了du[i]>=d[i]了

然后考虑为什么要把e-e'连起来排一般图最大匹配,因为你二分图最大匹配最后连上的那些边化作的点,每一个连通块不一定会用对应的边,而如果把e-e'连起来,如果某个u-e配对了,e'没有个某个v连起来,那么e'他就落单了,就必不可能是完美匹配

#include
using namespace std;

const int maxl=1010;
const int N=1010;

int n,m,ans,tot;
int du[maxl],d[maxl],l[maxl],r[maxl],lm[maxl],rm[maxl];
struct edge
{
	int u,v;
}ed[maxl];
vector e[maxl];
struct Blossom{
    int mate[N],n,ret,nex[N],f[N],mark[N],vis[N],t;
    queue Q;
    int F(int x){return x==f[x]?x:f[x]=F(f[x]); }
    void merge(int x,int y){ f[F(x)]=F(y); }
    int lca(int x,int y){
        for(t++;;swap(x,y)){
            if(~x){
                if(vis[x=F(x)]==t) return x; vis[x]=t;
                x=mate[x]!=-1?nex[mate[x]]:-1;
            }
        }
    }
    void group(int a,int p){
        for(int b,c;a!=p;merge(a,b),merge(b,c),a=c){
            b=mate[a],c=nex[b];
            if(F(c)!=p) nex[c]=b;
            if(mark[b]==2) mark[b]=1,Q.push(b);
            if(mark[c]==2) mark[c]=1,Q.push(c);
        }
    }
    void aug(int s,const vector G[]){
        for(int i=0;i G[]){
        n=_n; for(int i=0;ii;
        return ret*2==n;
    }
}blo;

inline void prework()
{
	for(int i=1;i<=n;i++)
		scanf("%d",&d[i]),du[i]=0;
	int u,v;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&u,&v);
		ed[i]=edge{u,v};
		++du[u];++du[v];
	}
	ans=1;tot=0;
	for(int i=1;i<=n;i++)
	{
		if(du[i]

 

你可能感兴趣的:(带花树)