很明显是最大二分匹配,但是也可以用最大流实现,加一个源点,和一个汇点建图求最大流也可以求解
错了两天,原因很蛋疼:
1,建图时,忘记了牛和牛栏是存在一维数组里的,所以N头牛存成1~N的话(我是这样建图的),牛栏应该是(N+1)~(N+M),而不是从1到M。这个真的是很悲催……
2,就是下面代码里的那个队列了,如果新建队列是在while(1)外面的话,在while(1)里面就应该做清空操作,当然新建在里面的话会跟着循环一起更新,所以就不用了。因为这个,我TL了两次……
思想嘛,还是传统的增广路最大流,代码如下:
#include <cstdio> #include <cstdlib> #include <iostream> #include <string.h> #include <queue> #include <limits.h> #define N 420 #define min(a,b) a<b?a:b using namespace std; int n,m,map[N][N],flow[N][N],minflow[N],pre[N]; void getmap() { int i,k,x; memset(map,0,sizeof(map)); for(i=1;i<=n;i++) { scanf("%d",&k); while(k--) { scanf("%d",&x); map[i][n+x]=1; } } for(i=1;i<=n;i++) map[0][i]=1; for(i=n+1;i<=n+m;i++) map[i][n+m+1]=1; } int maxflow(int s,int t) { int cur,u,v,ans=0; queue<int> q; memset(flow,0,sizeof(flow)); while(1) { memset(pre,-1,sizeof(pre)); memset(minflow,0,sizeof(minflow)); while(!q.empty()) //注意!!!!!! q.pop(); q.push(s); minflow[s]=INT_MAX; while( !q.empty() ) { cur=q.front(); q.pop(); if(cur==t)break; for(v=s;v<=t;v++) { if(pre[v]<0 && map[cur][v]-flow[cur][v]>0) { q.push(v); pre[v]=cur; minflow[v]=min(minflow[cur],map[cur][v]-flow[cur][v]); } } } if(pre[t]==-1)break; for(v=t;v!=s;v=pre[v]) { u=pre[v]; flow[u][v]+=minflow[t]; flow[v][u]-=minflow[t]; } ans+=minflow[t]; } return ans; } int main() { while(~scanf("%d%d",&n,&m)) { getmap(); printf("%d/n",maxflow(0,n+m+1)); } return 0; }