挑战NPC
%%%VFK,神建图
题目要求“半空的”筐子数最多
我们把每个筐子拆成3个槽,两两连边,形成一个三元环。然后对读入的可行配对,由小球分别向三个筐子连边。
进行匹配时我们发现,三元环内会形成一条匹配边,当且仅当筐子为“半空的”。
这样就转化成了一般图最大匹配,Ans=最大匹配-n
学习了一个带花树
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define maxn 605 4 #define maxm 90105 5 int cnt,v[maxm<<1],next[maxm<<1],first[maxn]; 6 int tot,T,tmd,head,tail,match[maxn],vis[maxn],fa[maxn],lst[maxn],mrk[maxn],q[maxn]; 7 int read(){ 8 int tmp=0; 9 char ch=0; 10 while(!isdigit(ch))ch=getchar(); 11 while(isdigit(ch)){ 12 tmp=tmp*10+ch-'0'; 13 ch=getchar(); 14 } 15 return tmp; 16 } 17 void clr(){ 18 memset(first,0,sizeof(first)); 19 cnt=0; 20 memset(match,0,sizeof(match)); 21 memset(vis,0,sizeof(vis)); 22 } 23 void add(int st,int end){ 24 v[++cnt]=end; 25 next[cnt]=first[st]; 26 first[st]=cnt; 27 } 28 void link(int a,int b){ add(a,b),add(b,a); } 29 int gf(int x){ return fa[x]==x?x:gf(fa[x]); } 30 void un(int a,int b){ fa[gf(a)]=gf(b); } 31 int lca(int a,int b){ 32 tmd++; 33 while(1){ 34 if(a){ 35 a=gf(a); 36 if(vis[a]==tmd)return a; 37 vis[a]=tmd; 38 if(match[a])a=lst[match[a]]; 39 else a=0; 40 } 41 swap(a,b); 42 } 43 } 44 void haha(int x,int p){ 45 while(x!=p){ 46 int a=match[x],b=lst[a]; 47 if(gf(b)!=p)lst[b]=a; 48 if(mrk[a]==2)mrk[q[++tail]=a]=1; 49 if(mrk[b]==2)mrk[q[++tail]=b]=1; 50 un(x,a),un(a,b); 51 x=b; 52 } 53 } 54 void find(int s){ 55 for(int i=1;i<=tot;i++) 56 lst[i]=mrk[i]=0,fa[i]=i; 57 head=tail=0; 58 q[++tail]=s,mrk[s]=1; 59 while(head<tail){ 60 int x=q[++head]; 61 for(int e=first[x];e;e=next[e]){ 62 if(gf(v[e])==gf(x)||mrk[v[e]]==2||v[e]==match[x])continue; 63 if(mrk[v[e]]==1){ 64 int p=lca(x,v[e]); 65 if(gf(x)!=p)lst[x]=v[e]; 66 if(gf(v[e])!=p)lst[v[e]]=x; 67 haha(x,p),haha(v[e],p); 68 } 69 else if(!match[v[e]]){ 70 int nw; 71 lst[nw=v[e]]=x; 72 while(nw){ 73 x=lst[nw]; 74 int tmp=match[x]; 75 match[x]=nw,match[nw]=x; 76 nw=tmp; 77 } 78 return; 79 } 80 else{ 81 lst[v[e]]=x; 82 mrk[v[e]]=2; 83 mrk[q[++tail]=match[v[e]]]=1; 84 } 85 } 86 } 87 } 88 int main(){ 89 scanf("%d",&T); 90 while(T--){ 91 clr(); 92 int n,m,E; 93 scanf("%d%d%d",&n,&m,&E); 94 tot=n+3*m; 95 for(int i=1;i<=E;i++){ 96 int a,b; 97 scanf("%d%d",&a,&b); 98 for(int j=1;j<=3;j++) 99 link(a,n+(b-1)*3+j); 100 } 101 for(int i=1;i<=m;i++) 102 link(n+(i-1)*3+1,n+(i-1)*3+2); 103 for(int i=1;i<=tot;i++) 104 if(!match[i])find(i); 105 int ans=0; 106 for(int i=1;i<=tot;i++) 107 if(match[i])ans++; 108 printf("%d\n",ans/2-n); 109 for(int i=1;i<=n;i++) 110 printf("%d ",(match[i]-n-1)/3+1); 111 printf("\n"); 112 } 113 return 0; 114 }