图论:匈牙利算法
其实在写这个的代码的时候我是纳闷的,X集合和Y集合的点,能同时用1,或者2来表示吗?
然后我努力说服自己:它已经是二分图了
它就是存了一个 → 而已
好的我被自己说服了
二分图匹配说的就是,每个人有若干种选择,但是每种选择只能容纳一个人,问你最多能配对多少
或者说成选边的时候不能经过同一个点
最大匹配就是最多选择多少条边的问题
匈牙利算法就是,有机会就上,没机会要创造机会也要上,尽可能地给当前腾地方,腾的过程是一个递归的过程
其实这个算法挺矫情的。。
bool find(int u) { for(int tmp=g[u];tmp;tmp=e[tmp].next) if(!y[e[tmp].t]) { y[e[tmp].t]=1; if(lk[e[tmp].t]==0||find(lk[e[tmp].t])) { lk[e[tmp].t]=u; return 1; } } return 0; }
建图之后,对于每个X中的点,清空y数组之后find就好了
然后忘了说定义了,补上。。
int n,m,cnt,ans; int y[maxn],lk[maxn],g[maxn];
y记录的是Y中的下标节点是否被访问过
lk记录的是与当前下标节点(Y中)相连的X中的节点
然后给出完整实现:
1 #include<cstdio> 2 #include<cstring> 3 const int maxn=205; 4 const int maxm=205; 5 int n,m,cnt,ans; 6 int y[maxn],lk[maxn],g[maxn]; 7 struct Edge{int t,next;}e[maxn*maxm]; 8 void addedge(int u,int v) 9 { 10 e[++cnt].t=v;e[cnt].next=g[u]; 11 g[u]=cnt; 12 } 13 bool find(int u) 14 { 15 for(int tmp=g[u];tmp;tmp=e[tmp].next) 16 if(!y[e[tmp].t]) 17 { 18 y[e[tmp].t]=1; 19 if(lk[e[tmp].t]==0||find(lk[e[tmp].t])) 20 { 21 lk[e[tmp].t]=u; 22 return 1; 23 } 24 } 25 return 0; 26 } 27 int main() 28 { 29 scanf("%d%d",&n,&m); 30 int tmp,tmp1; 31 for(int i=1;i<=n;i++) 32 { 33 scanf("%d",&tmp); 34 for(int j=1;j<=tmp;j++) 35 { 36 scanf("%d",&tmp1); 37 addedge(i,tmp1); 38 } 39 } 40 for(int i=1;i<=n;i++) 41 { 42 memset(y,0,sizeof(y)); 43 if(find(i)) ans++; 44 } 45 printf("%d",ans); 46 return 0; 47 }
老实说,这个算法,真的很神奇。。