# ACM算法总结 一般图最大匹配

const int maxn=1005;
const int maxm=1e6+5;

struct daihuashu
{
struct edge {int v,nxt;} e[maxm];
int n,m,que[maxm],ql,qr,pre[maxn],tim=0,ans=0;
int h[maxn],tot=0,match[maxn],f[maxn],tp[maxn],tic[maxn];

daihuashu() {}
daihuashu(int n,int m) {this->n=n; this->m=m;}

void init(int n=0,int m=0)
{
tim=ans=ql=qr=tot=0;
this->n=n; this->m=m;
mem(match,0); mem(tic,0); mem(h,0);
}

int find(int x) {return f[x]==x?x:f[x]=find(f[x]);}
void add(int u,int v) {e[++tot]=(edge){v,h[u]}; h[u]=tot;}
int lca(int x,int y)
{
for(++tim;;swap(x,y)) if(x)
{
x=find(x);
if(tic[x]==tim) return x;
else tic[x]=tim,x=pre[match[x]];
}
}
void shrink(int x,int y,int p)
{
while(find(x)!=p)
{
pre[x]=y; y=match[x];
if(tp[y]==2) tp[y]=1,que[++qr]=y;
if(find(x)==x) f[x]=p;
if(find(y)==y) f[y]=p;
x=pre[y];
}
}
bool aug(int s)
{
REP(i,1,n) f[i]=i;
mem(tp,0); mem(pre,0); tp[que[ql=qr=1]=s]=1;
while(ql<=qr)
{
int x=que[ql++];
for(int i=h[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v)
{
if(find(v)==find(x) || tp[v]==2) continue;
if(!tp[v])
{
tp[v]=2; pre[v]=x;
if(!match[v])
{
for(int now=v,last,tmp;now;now=last)
last=match[tmp=pre[now]],match[now]=tmp,match[tmp]=now;
return true;
}
tp[match[v]]=1; que[++qr]=match[v];
}
else if(tp[v]==1)
{
int l=lca(x,v);
shrink(x,v,l); shrink(v,x,l);
}
}
}
return false;
}
void run() {REP(i,1,n) ans+=(!match[i] && aug(i));}
}dhs;


• 一道例题 Hard Problem ：有一个无向图，现在为每个结点指定一个非负整数 d[i]，问能否从无向图中构造一个子图，使得每个结点的度为 d[i] 。

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> P;
{
int x=0,flag=1; char c=getchar();
while((c>'9' || c<'0') && c!='-') c=getchar();
if(c=='-') flag=0,c=getchar();
while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return flag?x:-x;
}

const int maxn=1005;
const int maxm=1e6+5;

struct daihuashu
{
struct edge {int v,nxt;} e[maxm];
int n,m,que[maxm],ql,qr,pre[maxn],tim=0,ans=0;
int h[maxn],tot=0,match[maxn],f[maxn],tp[maxn],tic[maxn];

daihuashu() {}
daihuashu(int n,int m) {this->n=n; this->m=m;}

void init(int n=0,int m=0)
{
tim=ans=ql=qr=tot=0;
this->n=n; this->m=m;
mem(match,0); mem(tic,0); mem(h,0);
}

int find(int x) {return f[x]==x?x:f[x]=find(f[x]);}
void add(int u,int v) {e[++tot]=(edge){v,h[u]}; h[u]=tot;}
int lca(int x,int y)
{
for(++tim;;swap(x,y)) if(x)
{
x=find(x);
if(tic[x]==tim) return x;
else tic[x]=tim,x=pre[match[x]];
}
}
void shrink(int x,int y,int p)
{
while(find(x)!=p)
{
pre[x]=y; y=match[x];
if(tp[y]==2) tp[y]=1,que[++qr]=y;
if(find(x)==x) f[x]=p;
if(find(y)==y) f[y]=p;
x=pre[y];
}
}
bool aug(int s)
{
REP(i,1,n) f[i]=i;
mem(tp,0); mem(pre,0); tp[que[ql=qr=1]=s]=1;
while(ql<=qr)
{
int x=que[ql++];
for(int i=h[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v)
{
if(find(v)==find(x) || tp[v]==2) continue;
if(!tp[v])
{
tp[v]=2; pre[v]=x;
if(!match[v])
{
for(int now=v,last,tmp;now;now=last)
last=match[tmp=pre[now]],match[now]=tmp,match[tmp]=now;
return true;
}
tp[match[v]]=1; que[++qr]=match[v];
}
else if(tp[v]==1)
{
int l=lca(x,v);
shrink(x,v,l); shrink(v,x,l);
}
}
}
return false;
}
void run() {REP(i,1,n) ans+=(!match[i] && aug(i));}

int from[maxn],to[maxn],du[maxn];
void solve()
{
int cnt=0;
VI di[maxn];
REP(i,1,m)
{
from[i]=x; to[i]=y;
}
REP(i,1,n) REP(j,1,du[i]) di[i].pb(++cnt);
REP(i,1,m)
{
int x=from[i],y=to[i];
cnt+=2;
}
n=cnt;
run();
int flag=1;
REP(i,1,n) if(!match[i]) flag=0;
puts(flag?"YES":"NO");
}
}dhs;

int main()
{
REP(i,1,T)
{
printf("Case %d: ",i);
dhs.init();
dhs.solve();
}

return 0;
}

03-03
11-07 5749

04-10 978
02-23 2248
03-30 109
12-15 52
08-30 981
03-09 3236
08-28 1万+