题意:
有n(n ≤ 1000)个人和m(m≤500)个组。一个人可能属于很多组。现在请你从某些组中去掉几个人,使得每个人只属于一个组,并使得人数最多的组中人员数目最小。
分析:看到最多的最小,就可以猜到是一个二分答案ans的题,最大流是没想到...囧.
这题用最大流做,若Ai属于Bi,则连一条Ai到Bi的边,边值为1,然后连超级源点S到Ai的边,边值为1,表示仅有一个Ai,然后对于超级源点T,连Bi到T的边,边值为ans,表示Bi组织最多有ans个人,求最大流,若最大流答案等于n,则表示在每组人限制ans个的情况下能够分配组员到各组,若不等于,则说明在每组人限制ans个的情况下,不能分配组员到各组;
// File Name: 1345.cpp // Author: Zlbing // Created Time: 2013/4/22 14:14:53 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define REP(i,r,n) for(int i=r;i<=n;i++) #define RREP(i,n,r) for(int i=n;i>=r;i--) const int MAXN=2005; int n,m; struct Edge{ int from,to,cap,flow; }; bool cmp(const Edge& a,const Edge& b){ return a.from < b.from || (a.from == b.from && a.to < b.to); } struct Dinic{ int n,m,s,t; vector<Edge> edges; vector<int> G[MAXN]; bool vis[MAXN]; int d[MAXN]; int cur[MAXN]; void init(int n){ this->n=n; for(int i=0;i<=n;i++)G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap){ edges.push_back((Edge){from,to,cap,0}); edges.push_back((Edge){to,from,0,0});//当是无向图时,反向边容量也是cap,有向边时,反向边容量是0 m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BFS(){ CL(vis,0); queue<int> Q; Q.push(s); d[s]=0; vis[s]=1; while(!Q.empty()){ int x=Q.front(); Q.pop(); for(int i=0;i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if(!vis[e.to]&&e.cap>e.flow){ vis[e.to]=1; d[e.to]=d[x]+1; Q.push(e.to); } } } return vis[t]; } int DFS(int x,int a){ if(x==t||a==0)return a; int flow=0,f; for(int& i=cur[x];i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0){ e.flow+=f; edges[G[x][i]^1].flow-=f; flow+=f; a-=f; if(a==0)break; } } return flow; } //当所求流量大于need时就退出,降低时间 int Maxflow(int s,int t,int need){ this->s=s;this->t=t; int flow=0; while(BFS()){ CL(cur,0); flow+=DFS(s,INF); if(flow>need)return flow; } return flow; } //最小割割边 vector<int> Mincut(){ BFS(); vector<int> ans; for(int i=0;i<edges.size();i++){ Edge& e=edges[i]; if(vis[e.from]&&!vis[e.to]&&e.cap>0)ans.push_back(i); } return ans; } void Reduce(){ for(int i = 0; i < edges.size(); i++) edges[i].cap -= edges[i].flow; } void ClearFlow(){ for(int i = 0; i < edges.size(); i++) edges[i].flow = 0; } }; vector<int> T[MAXN]; Dinic solver; bool solve(int mid) { solver.init(n+m); int s=0,t=n+m+1; REP(i,1,n) { solver.AddEdge(s,i,1); REP(j,0,T[i].size()) { solver.AddEdge(i,n+T[i][j]+1,1); } } REP(i,1,m) { solver.AddEdge(n+i,t,mid); } int ans=solver.Maxflow(s,t,INF); if(ans==n)return true; else return false; } int main() { while(~scanf("%d%d",&n,&m)) { if(n==0&&m==0)break; REP(i,0,n)T[i].clear(); char ch[20]; REP(i,1,n) { scanf("%s",ch); char c; int a; c=getchar(); //printf("aaacccc%caaa\n",c); while(c!='\n') { scanf("%d",&a); //printf("aa%d\n",a); T[i].push_back(a); c=getchar(); //printf("cccc%caa\n",c); } } int L=0,R=n; while(L<R) { int mid=(R+L)/2; printf("mid--%d\n",mid); if(solve(mid)) { R=mid; } else{ L=mid+1; } } printf("%d\n",L); } return 0; }