题意:
舞会上,男孩和女孩配对,求最大完全匹配个数,要求每个人最多与k个不喜欢的人配对,且每次都和不同的人配对。
分析:
将一个点拆成3个点. b, b1, b2. 从1到n枚举ans, 判可行流. 源点s到每个b连一容量为ans边, b->b1容量inf, b->b2容量为k, 每个g到汇点连一容量为ans的边, g->g1容量inf, g->g2容量为k, 如果一个boy喜欢一个girl, 则连一条边b1->g1, 容量为1, 如果一个boy讨厌一个girl, 则b2->g2, 容量为1.
满足可行流条件: 最大流==ans*n. (n为boy或者girl数)
// File Name: 1024.cpp // Author: Zlbing // Created Time: 2013/9/11 18:44:02 #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=1000; struct Edge{ int from,to,cap,flow; Edge() { } Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(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<(int)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<(int)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; } }; int n,m,k; int s,t; Dinic solver; int G[105][105]; bool solve(int x) { solver.init(t+1); REP(i,1,n) REP(j,1,n) { if(G[i][j]==1) { solver.AddEdge(2*n+i,2*n+j+n,1); //printf("%d %d cap=%d\n",2*n+i,2*n+j+n,1); } else { solver.AddEdge(2*n*2+i,2*n*2+n+j,1); //printf("%d %d cap=%d\n",2*n*2+i,2*n*2+j+n,1); } } REP(i,1,n) { solver.AddEdge(s,i,x); //printf("%d %d cap=%d\n",s,i,x); solver.AddEdge(i,2*n+i,INF); //printf("%d %d cap=%d\n",i,2*n+i,INF); solver.AddEdge(i,2*n*2+i,k); //printf("%d %d cap=%d\n",i,2*n*2+i,k); } REP(i,1+n,n+n) { solver.AddEdge(i,t,x); //printf("%d %d cap=%d\n",i,t,x); solver.AddEdge(2*n+i,i,INF); //printf("%d %d cap=%d\n",2*n+i,i,INF); solver.AddEdge(2*n*2+i,i,k); //printf("%d %d cap=%d\n",2*n*2+i,i,k); } int ans=solver.Maxflow(s,t,INF); if(ans>=n*x) return true; else return false; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&m,&k); s=n*2*3+1;; t=s+1; int a,b; CL(G,0); REP(i,1,m) { scanf("%d%d",&a,&b); G[a][b]=1; } int ans=0; for(int i=n;i>0;i--) { //printf("Case %d:\n",i); if(solve(i)) { ans=i; break; } } printf("%d\n",ans); } return 0; }