Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 10196 | Accepted: 4757 |
Description
Input
Output
Sample Input
5 5 2 2 5 3 2 3 4 2 1 5 3 1 2 5 1 2
Sample Output
4
Source
分析:纯二分图最大匹配,适合拿来练二分图算法。。。嘿嘿
附上三种实现方法:
bfs过程:
#include<stdio.h> const int MAX=201; int n,m,map[MAX][MAX]; int EdmondsBFS() { int i,j,x,ans=0; int q[MAX],prev[MAX],qs,qe;//q是BFS用的队列,prev是用来记录交错链的,同时也用来记录右边的点是否被找过 int vm1[MAX],vm2[MAX];//vm1,vm2分别表示两边的点与另一边的哪个点相匹配 for(i=1;i<=n;++i)vm1[i]=-1; for(i=1;i<=m;++i)vm2[i]=-1;//初始化所有点为未被匹配的状态 for(i=1;i<=n;++i) { if(vm1[i]!=-1)continue;//对于左边每一个未被匹配的点进行一次BFS找交错链 for(j=1;j<=m;++j)prev[j]=-2; //每次BFS时初始化右边的点 qs=qe=0; //初始化BFS的队列 //下面这部分代码从初始的那个点开始,先把它能找的的右边的点放入队列 for(j=1;j<=map[i][0];++j) prev[map[i][j]]=-1,q[qe++]=map[i][j]; while(qs<qe) { x=q[qs]; if(vm2[x]==-1)break; //如果找到一个未被匹配的点,则结束,找到了一条交错链 ++qs; //下面这部分是扩展结点的代码 for(j=1;j<=map[vm2[x]][0];++j) if(prev[map[vm2[x]][j]]==-2)prev[map[vm2[x]][j]]=x,q[qe++]=map[vm2[x]][j]; //如果该右边点是一个已经被匹配的点,则vm2[x]是与该点相匹配的左边点 //从该左边点出发,寻找其他可以找到的右边点 } if(qs==qe)continue;//没有找到交错链 //更改交错链上匹配状态 while(prev[x]>-1) { vm1[vm2[prev[x]]]=x; vm2[x]=vm2[prev[x]]; x=prev[x]; } vm1[i]=x; vm2[x]=i; ++ans; } return ans; } int main(int argc, char* argv[]) { int i,j; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;++i) { for(j=1;j<=m;++j)map[i][j]=0; scanf("%d",&map[i][0]); for(j=1;j<=map[i][0];++j)scanf("%d",&map[i][j]); } printf("%d/n",EdmondsBFS()); } }
dfs实现过程:
#include<stdio.h> const int MAXN=201; int link[MAXN],will[MAXN][MAXN],n,m,ans; bool v[MAXN]; bool EdmondsDFS(int s) { for(int i=1;i<=will[s][0];++i) if(v[will[s][i]]) { v[will[s][i]]=0; if(!link[will[s][i]]||EdmondsDFS(link[will[s][i]])) { link[will[s][i]]=s; return 1; } } return 0; } int main(int argc, char* argv[]) { int i,j; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;++i) { scanf("%d",&will[i][0]); for(j=1;j<=will[i][0];++j)scanf("%d",&will[i][j]); } for(i=1;i<=m;++i)link[i]=0; ans=0; for(i=1;i<=n;++i) { for(j=1;j<=m;++j)v[j]=1; ans+=EdmondsDFS(i); } printf("%d/n",ans); } }
Hopcroft-KarpDFS算法:
#include <iostream> using namespace std; const int maxn=201; const int maxm=40005; const int INF=INT_MAX/2; struct EDGE { int b; int next; }; int nx, ny, m; EDGE edge[maxm]; int edge_num; int first[maxn]; int cx[maxn],cy[maxn];// cx[i]表示xi对应的匹配,cy[i]表示yi对应的匹配. int distx[maxn],disty[maxn]; // 层的概念,即在BFS中的第几层. int que[maxn]; int ans; inline void Init() { fill(cx,cx+maxn,-1); fill(cy,cy+maxn,-1); fill(first,first+maxn,-1); edge_num=0; ans=0; } inline void AddEdge(int a, int b) { edge[edge_num].b=b; edge[edge_num].next=first[a],first[a]=edge_num++; } inline bool BFS() { int i,j,k; bool flag(0); int h,t; memset(distx,0,sizeof(distx)); memset(disty,0,sizeof(disty)); h=t=0; for(i=1;i<=nx;++i) if(cx[i]==-1)que[t++]=i; for(;h!=t;++h) { i=que[h]; for(k=first[i];k!=-1;k=edge[k].next) { j=edge[k].b; if(!disty[j]) { disty[j]=distx[i]+1; if(cy[j]==-1)flag=1; else distx[cy[j]]=disty[j]+1,que[t++]=cy[j]; } } } return flag; } bool DFS(int i) { int j,k; for (k=first[i];k!=-1;k=edge[k].next) { j=edge[k].b; if(disty[j]==distx[i]+1) { // 说明j是i的后继结点. disty[j]=0; // j被用过了,不能再作为其他点的后继结点了. if(cy[j]==-1||DFS(cy[j])) { cx[i]=j,cy[j]=i; return 1; } } } return 0; } inline void Hopcroft_Karp() { int i,j; while(BFS()) for(i=1;i<=nx;++i) if(cx[i]==-1 && DFS(i))++ans; } int main(void) { // freopen("Input.txt", "r", stdin); int i, j; int a, b; while (scanf("%d%d",&nx,&ny)!=EOF) { Init(); for(i=1;i<=nx;++i) { scanf("%d",&a); for(b=0;b<a;++b)scanf("%d",&j),AddEdge(i, j); } Hopcroft_Karp(); printf("%d/n", ans); } return 0; }