POJ2289 Jamie's Contact Groups 二分+最大流匹配

来源:互联网 发布:北京私立汇佳学校 知乎 编辑:程序博客网 时间:2024/04/29 11:44

题目:给定人名和群组的关系,叫你把每个人分配到某个群组的关系,使这个分配方案满足最大的那个群组人数 最小。

思路:

二分图匹配。

求法是用二分答案加最大流判定。


#include<iostream>using namespace std;#define MIN(a,b) (a<b?a:b)const int N=1505,M=1100005;const int inf=(1<<29);char name[20];int n,m;struct Edge{int v,next,w,re;}edge[M];int edgehead[N];int k=1;int level[N];int visit[N];int que[N];void addedge(int u,int v,int w){edge[k].v=v;edge[k].w=w;edge[k].next=edgehead[u];edge[k].re=k+1;edgehead[u]=k++;edge[k].v=u;edge[k].w=0;edge[k].next=edgehead[v];edge[k].re=k-1;edgehead[v]=k++;}int match[1005][505];bool bfs(){memset(visit,0,sizeof(visit));memset(level,0,sizeof(level));visit[0]=true;level[0]=0;int head=1,tail=1;que[tail++]=0;while(head<tail){int now=que[head++];if(now==n+m+1){return true;}for(int i=edgehead[now];i;i=edge[i].next){int v=edge[i].v;if(!visit[v]&&edge[i].w>0){level[v]=level[now]+1;visit[v]=true;que[tail++]=v;}}}return false;}int dinic(int now,int sum){if(now==n+1+m)return sum;int os=sum;for(int i=edgehead[now];i&∑>0;i=edge[i].next){int v=edge[i].v;if(level[v]==level[now]+1&&edge[i].w>0){int tmp=dinic(v,MIN(edge[i].w,sum));edge[i].w-=tmp;edge[edge[i].re].w+=tmp;sum-=tmp;}}return os-sum;}bool make(int val){memset(edge,0,sizeof(edge));memset(edgehead,0,sizeof(edgehead));k=1;for(int i=1;i<=n;i++){addedge(0,i,1);for(int j=1;match[i][j]!=-1;j++){addedge(i,match[i][j]+n+1,1);}}for(int i=1;i<=m;i++){addedge(i+n,n+1+m,val);}int ans=0;while(bfs()){ans+=dinic(0,inf);}if(ans==n){return true;}else{return false;}}int main(){//freopen("C:\\Users\\wuyanyisb\\Desktop\\1.txt","r",stdin);while(scanf("%d%d",&n,&m),n!=0||m!=0){memset(match,0,sizeof(match));for(int i=1;i<=n;i++){scanf("%s",name);char ch;int to;ch=getchar();int j=1;while(ch!='\n'){scanf("%d",&match[i][j]);ch=getchar();j++;}match[i][j]=-1;}int s=0,t=n+1;while(s<t){int mid=(s+t)/2;if(make(mid)){t=mid;}else{s=mid+1;}}printf("%d\n",s);}return 0;}