LA 3268 号码簿分组(最大流+二分)
Posted 谦谦君子,陌上其华
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LA 3268 号码簿分组(最大流+二分)相关的知识,希望对你有一定的参考价值。
https://vjudge.net/problem/UVALive-3268
题意:
有n个人和m个组。一个人可能属于很多组。现在请你从某些组中去掉几个人,使得每个人只属于一个组,并使得人数最多的组中人员数目为最小值。
思路:
建立超级源汇点,源点和每个人相连,容量为1,说明每个人最多只能在一个组中。每个人和可以属于的组相连,容量为1。接下来枚举组的最大容量值,将每组和汇点相连,容量为枚举值,二分跑最大流即可。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<sstream> 6 #include<vector> 7 #include<stack> 8 #include<queue> 9 #include<cmath> 10 #include<map> 11 #include<set> 12 using namespace std; 13 typedef long long ll; 14 typedef pair<int,int> pll; 15 const int INF = 0x3f3f3f3f; 16 const int maxn = 2000 + 5; 17 18 vector<int> g[maxn]; 19 20 struct Edge 21 { 22 int from,to,cap,flow; 23 Edge(int u,int v,int w,int f):from(u),to(v),cap(w),flow(f){} 24 }; 25 26 struct Dinic 27 { 28 int n,m,s,t; 29 vector<Edge> edges; 30 vector<int> G[maxn]; 31 bool vis[maxn]; 32 int cur[maxn]; 33 int d[maxn]; 34 35 void init(int n) 36 { 37 this->n=n; 38 for(int i=0;i<n;++i) G[i].clear(); 39 edges.clear(); 40 } 41 42 void AddEdge(int from,int to,int cap) 43 { 44 edges.push_back( Edge(from,to,cap,0) ); 45 edges.push_back( Edge(to,from,0,0) ); 46 m=edges.size(); 47 G[from].push_back(m-2); 48 G[to].push_back(m-1); 49 } 50 51 bool BFS() 52 { 53 queue<int> Q; 54 memset(vis,0,sizeof(vis)); 55 vis[s]=true; 56 d[s]=0; 57 Q.push(s); 58 while(!Q.empty()) 59 { 60 int x=Q.front(); Q.pop(); 61 for(int i=0;i<G[x].size();++i) 62 { 63 Edge& e=edges[G[x][i]]; 64 if(!vis[e.to] && e.cap>e.flow) 65 { 66 vis[e.to]=true; 67 d[e.to]=d[x]+1; 68 Q.push(e.to); 69 } 70 } 71 } 72 return vis[t]; 73 } 74 75 int DFS(int x,int a) 76 { 77 if(x==t || a==0) return a; 78 int flow=0, f; 79 for(int &i=cur[x];i<G[x].size();++i) 80 { 81 Edge &e=edges[G[x][i]]; 82 if(d[e.to]==d[x]+1 && (f=DFS(e.to,min(a,e.cap-e.flow) ) )>0) 83 { 84 e.flow +=f; 85 edges[G[x][i]^1].flow -=f; 86 flow +=f; 87 a -=f; 88 if(a==0) break; 89 } 90 } 91 return flow; 92 } 93 94 int Maxflow(int s,int t) 95 { 96 this->s=s; this->t=t; 97 int flow=0; 98 while(BFS()) 99 { 100 memset(cur,0,sizeof(cur)); 101 flow +=DFS(s,INF); 102 } 103 return flow; 104 } 105 }DC; 106 107 int n, m; 108 int src, dst; 109 110 bool solve(int x) 111 { 112 DC.init(dst+1); 113 for(int i=1;i<=n;i++) 114 { 115 DC.AddEdge(src,i,1); 116 for(int j=0;j<g[i].size();j++) 117 { 118 DC.AddEdge(i,g[i][j]+n+1,1); 119 } 120 } 121 for(int i=1;i<=m;i++) 122 DC.AddEdge(i+n,dst,x); 123 124 if(DC.Maxflow(src,dst)==n) return true; 125 else return false; 126 } 127 128 int main() 129 { 130 //freopen("in.txt","r",stdin); 131 while(~scanf("%d%d",&n,&m) && (n+m)) 132 { 133 for(int i=1;i<=n;i++) g[i].clear(); 134 src=0, dst=n+m+1; 135 136 for(int i=1;i<=n;i++) 137 { 138 char name[20]; char c; int x; 139 140 cin>>name; 141 while(~scanf("%d%c",&x,&c)) 142 { 143 g[i].push_back(x); 144 if(c==‘\n‘) break; 145 } 146 } 147 148 int ans=0; 149 int L=0,R=n; 150 while(L<=R) 151 { 152 int mid=(L+R)/2; 153 if(solve(mid)) {ans=mid;R=mid-1;} 154 else L=mid+1; 155 } 156 printf("%d\n",ans); 157 } 158 return 0; 159 }
以上是关于LA 3268 号码簿分组(最大流+二分)的主要内容,如果未能解决你的问题,请参考以下文章