题目链接在这里:B (codeforces.com)
答案要求两女夹一男的匹配数,很显然不能用一般的二分图匹配去做,但是这既然是个匹配问题,题目是人出出来的,很显然还是需要转化成我们平时做的那种匹配。所以我们考虑把男生拆开拆成两个点,然后跑一般图匹配。最后拿匹配数减去男生人数就是结果。这就是一个带花树问题,我们知道,带花树匹配一定是间隔匹配,所以如果是答案要求的一对匹配,我们带花树会跑出两个(因为我们将男生拆成两个点看),而对于不合法的匹配(同一个男生自己跟自己匹配),那么最后减去男生人数的时候也把这个减掉了,所以结果是正确的。
后面遇到了匹配问题还是要想经典的二分图匹配和带花树,因为万变不离其宗,所有的匹配问题都是以这两个为出发点的。
1 #include "bits/stdc++.h" 2 using namespace std; 3 const int MAX=505; 4 int n,m,tot,cnt,fa[MAX]; 5 int head[MAX],nxt[MAX*MAX],adj[MAX*MAX]; 6 int vis[MAX],id[MAX],ff[MAX],mat[MAX],ans; 7 int q[2000005],st,ed; 8 char s[MAX]; 9 inline int getfather(int x){return (fa[x]==x?x:fa[x]=getfather(fa[x]));} 10 inline int read(){ 11 int an=0,x=1;char c=getchar(); 12 while (c<'0' || c>'9') {if (c=='-') x=-1;c=getchar();} 13 while (c>='0' && c<='9') {an=an*10+c-'0';c=getchar();} 14 return an*x; 15 } 16 inline void addedge(int u,int v){ 17 tot++; 18 adj[tot]=v; 19 nxt[tot]=head[u]; 20 head[u]=tot; 21 } 22 inline int lca(int x,int y){ 23 cnt++; 24 while (vis[x]!=cnt){ 25 if (x){ 26 x=getfather(x); 27 if (vis[x]==cnt) return x; 28 vis[x]=cnt; 29 if (mat[x]!=0) 30 x=getfather(ff[mat[x]]); 31 else x=0; 32 } 33 swap(x,y); 34 } 35 return x; 36 } 37 inline void work(int x,int y,int k){ 38 int z; 39 while (getfather(x)!=k){ 40 ff[x]=y; 41 z=mat[x]; 42 if (id[z]==1){ 43 id[z]=0; 44 q[++ed]=z; 45 } 46 if (getfather(z)==z) fa[z]=k; 47 if (getfather(x)==x) fa[x]=k; 48 y=z;x=ff[y]; 49 } 50 } 51 inline bool bfs(int x){ 52 int i,j,u,v; 53 int la,no,t,z; 54 for (i=1;i<=n;i++) fa[i]=i; 55 memset(id,-1,sizeof(id)); 56 st=ed=0; 57 q[++ed]=x;id[x]=0; 58 while (st<ed){ 59 u=q[++st]; 60 for (i=head[u];i;i=nxt[i]){ 61 v=adj[i]; 62 if (id[v]==-1){ 63 ff[v]=u,id[v]=1; 64 if (!mat[v]){ 65 no=v; 66 while (no){ 67 t=ff[no]; 68 la=mat[t]; 69 mat[t]=no;mat[no]=t; 70 no=la; 71 } 72 return true; 73 } 74 id[mat[v]]=0; 75 q[++ed]=mat[v]; 76 } 77 else if (id[v]==0 && getfather(u)!=getfather(v)){ 78 z=lca(u,v); 79 work(u,v,z);work(v,u,z); 80 } 81 } 82 } 83 return false; 84 } 85 int main(){ 86 freopen ("b.in","r",stdin);freopen ("b.out","w",stdout); 87 int i,j,u,v,cas; 88 scanf("%d",&cas); 89 while (cas--){ 90 n=read(),m=read(); 91 // scanf("%d %d",&n,&m); 92 ans=tot=cnt=0; 93 memset(head,0,sizeof(head)); 94 memset(ff,0,sizeof(ff)); 95 memset(vis,0,sizeof(vis)); 96 memset(mat,0,sizeof(mat)); 97 memset(fa,0,sizeof(fa)); 98 int now=n; 99 for (i=1;i<=n;i++){ 100 scanf("\n%s",s+1); 101 addedge(i,i+n); 102 addedge(i+n,i); 103 for (j=1;j<=m;j++) 104 if (s[j]=='1'){ 105 addedge(i,2*n+j); 106 addedge(2*n+j,i); 107 addedge(i+n,2*n+j); 108 addedge(2*n+j,i+n); 109 } 110 } 111 n=2*n+m; 112 for (i=1;i<=n;i++) 113 if (!mat[i] && bfs(i)) 114 ans++; 115 printf("%d\n",ans-now); 116 } 117 return 0; 118 }
未来是什么样,未来会发生什么,谁也不知道。
但是我知道,
起码从今天开始努力,
肯定比从明天开始努力,
要快一天实现梦想。
千里之行,始于足下! ——《那年那兔那些事儿》