点击查看原题
题目大意:一个(很恶俗的)交友游戏,男女搭配,女生选男生,选择的规则是可以选自己认可的也可以选自己的朋友(朋友的朋友,朋友的朋友的朋友)认可的。每轮可以选一个,并且下轮不能选已经被自己选过的。问最多可以玩几轮。
分析(建图):
因为一个团体可以选团体内任何人认可的人匹配,所以先并查集把团体分类,然后让内部每个女生都可以选团体可以选的男生,流量为1。
因为玩的轮数最多为n所以二分答案(k)去建立 源点到女生,男生到汇点的边容量为k。
跑最大流 如果 最大流等于n*k那么成立,二分答案。得到最终结果
AC代码:
#include<stdio.h>
#include<string.h>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define inf 100000000
using namespace std;
int n,m,k;
//最大流
struct tree
{
int from,to,cap,flow;
tree(){}
tree(int ff,int tt,int cc,int ww)
{
from=ff,to=tt,cap=cc,flow=ww;
}
};
vector<tree>G;
vector<int>v[300000];
int cur[300000];
int d[300000];
int que[3000000];
set<int> indirectfrd[505];
vector<int> directfrd[505];
void addtree(int from,int to,int cap)
{
G.push_back(tree(from,to,cap,0));
G.push_back(tree(to,from,0,0));
int m=G.size();
v[from].push_back(m-2);
v[to].push_back(m-1);
}
int sink,source;
bool bfs()
{
memset(d,-1,sizeof(d));
int front=0,back=0;
que[back++]=source;
d[source]=0;
while(front<back)
{
int p=que[front++];
if(p==sink) return true;
for(int i=0;i<v[p].size();i++)
{
tree &e=G[v[p][i]];
if(d[e.to]==-1&&e.flow<e.cap)
{
d[e.to]=d[p]+1;
que[back++]=e.to;
}
}
}
return false;
}
int dfs(int x,int a)
{
if(x==sink||a==0)
return a;
int flow=0,f;
for(int &i=cur[x];i<v[x].size();i++)
{
tree &e=G[v[x][i]];
if(d[e.to]==d[x]+1&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0)
{
e.flow+=f;
G[v[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0)
break;
}
}
if(!flow) d[x]=-2;
return flow;
}
int maxflow()
{
int flow=0;
while(bfs())
{
memset(cur,0,sizeof(cur));
flow+=dfs(source,inf);
}
return flow;
}
//并查集
int rankk[505];
int father[505];
void init()
{
for(int i=0;i<=n;i++)
{
rankk[i]=0;
father[i]=i;
}
}
int find(int x)
{
if(father[x]==x) return x;
else return father[x]=find(father[x]);
}
bool unite(int a,int b)
{
a=find(a);
b=find(b);
if(a==b) return false;
if(rankk[a]<rankk[b]) father[a]=b;
else
{
father[b]=a;
if(rankk[a]==rankk[b])
rankk[a]++;
}
return true;
}
bool getans(int mid)
{
for(int i=0;i<300000;i++)
{
v[i].clear();
}
G.clear();
source=1;sink=3*n;
for(int i=1;i<=n;i++)
{
addtree(source,i+1,mid);
addtree(i+n+1,sink,mid);
for(set<int>::iterator it=indirectfrd[i].begin();it!=indirectfrd[i].end();it++)
{
addtree((*it)+1,i+n+1,1);
}
}
if(maxflow()==mid*n)
return true;
return false;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&k);
init();
for(int i=0;i<=n;i++)
{
indirectfrd[i].clear();
directfrd[i].clear();
}
for(int i=0;i<m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
directfrd[a].push_back(b);
}
for(int i=0;i<k;i++)
{
int a,b;
scanf("%d%d",&a,&b);
unite(a,b);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(find(i)==find(j))
{
//printf("!! %d %d %d %d\n",i,j,find(i),find(j));
for(int l=0;l<directfrd[j].size();l++)
{
indirectfrd[i].insert(directfrd[j][l]);
}
}
}
}
//二分查找
int l=1,r=n;
while(l<=r)
{
int mid=(l+r)>>1;
if(getans(mid))
{
l=mid+1;
}
else
r=mid-1;
}
printf("%d\n",l-1);
}
}