poj 1274

 

The Perfect Stall
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 10196   Accepted: 4757

Description

Farmer John completed his new barn just last week, complete with all the latest milking technology. Unfortunately, due to engineering problems, all the stalls in the new barn are different. For the first week, Farmer John randomly assigned cows to stalls, but it quickly became clear that any given cow was only willing to produce milk in certain stalls. For the last week, Farmer John has been collecting data on which cows are willing to produce milk in which stalls. A stall may be only assigned to one cow, and, of course, a cow may be only assigned to one stall. 
Given the preferences of the cows, compute the maximum number of milk-producing assignments of cows to stalls that is possible. 

Input

The input includes several cases. For each case, the first line contains two integers, N (0 <= N <= 200) and M (0 <= M <= 200). N is the number of cows that Farmer John has and M is the number of stalls in the new barn. Each of the following N lines corresponds to a single cow. The first integer (Si) on the line is the number of stalls that the cow is willing to produce milk in (0 <= Si <= M). The subsequent Si integers on that line are the stalls in which that cow is willing to produce milk. The stall numbers will be integers in the range (1..M), and no stall will be listed twice for a given cow.

Output

For each case, output a single line with a single integer, the maximum number of milk-producing stall assignments that can be made.

Sample Input

5 5
2 2 5
3 2 3 4
2 1 5
3 1 2 5
1 2 

Sample Output

4

Source

USACO 40

分析:纯二分图最大匹配,适合拿来练二分图算法。。。嘿嘿

附上三种实现方法:

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; } 

你可能感兴趣的:(算法,Integer,input,each,output,Numbers)