题目大意:n个女生n个男生在一起玩耍,他们在玩一个“”结婚“的游戏,每局游戏女生找到一个男生作为自己的伴侣,每个女生可以找不和自己争吵的男生,如果一个女生和另外一个女生是好朋友,她也可以找和另外一个女生不争吵的男生作为自己的伴侣,另外有K次机会从所有的男生中选一个强制作为自己伴侣,每一局每个女生要找的男生都必须不相同,问这个游戏最多能进行多少局。
首先输入一个T代表T组样例,第二行输入四个整数,n,m,k,f,n代表有n个男生,n个女生,m代表男生女生的关系有m组,k代表女生有k次机会从所有男生中选一个作为伴侣,f代表女生和另一个女生认识的关系数量。
思路:首先一个女生要认识和另一个女生不争吵的男生我们可以用传递闭包来解决,floyd的第三层两个循环,一个是让女生之间互相认识,另一个是让女生认识男生。我们建立一个超级源点s=0,超级汇点t=3*n+1。超级源点连向每一个女生1~n,权值为我们二分寻找的答案mid,超级汇点连向每一个男生2*n~3*n,权值为我们二分要寻找的答案mid,然后我们把女生不争吵的男生之间连一条权值为1的边,代表这个女生可以直接找他。之后我们便要解决这个k了,k肯定是用在女生和可能争吵的男生之间的,我们把女生1~n和n+1~2*n之间连一条边权值为k的边,然后从n+1~2*n连向可能和女生争吵的男生之间,权值为1,这个拆点方法很巧妙,这样子跑一遍最大流,便是游戏最多的次数。
普通的dinic可能会超时,这里我用cur数组优化,代码如下:
#include
#include
#include
#include
#define inf 0x3fffffff
using namespace std;
const int maxn=255;
int first[maxn*3],sign,cur[255*3];
int s,t,d[maxn*3];
int mp[maxn*3][maxn*3];
int n,m,k,f;
struct node
{
int to,w,next;
}edge[maxn*maxn*maxn];
void creat()
{
memset(first,-1,sizeof(first));
sign=0;
}
void add_edge(int u,int v,int w)
{
edge[sign].to=v;
edge[sign].w=w;
edge[sign].next=first[u];
first[u]=sign++;
edge[sign].to=u;
edge[sign].w=0;
edge[sign].next=first[v];
first[v]=sign++;
}
int bfs()
{
queueq;
memset(d,0,sizeof(d));
d[s]=1;
q.push(s);
while(!q.empty())
{
int top=q.front();
q.pop();
for(int i=first[top];~i;i=edge[i].next)
{
int to=edge[i].to;
if(edge[i].w>0&&d[to]==0)
{
d[to]=d[top]+1;
if(to==t)
return 1;
q.push(to);
}
}
}
return d[t]!=0;
}
int dfs(int top,int flow)
{
if(top==t)
return flow;
int ans=0,x=0;
for(int i=cur[top];~i;i=edge[i].next)
{
int to=edge[i].to;
if(edge[i].w>0&&d[to]==d[top]+1)
{
x=dfs(to,min(flow-ans,edge[i].w));
edge[i].w-=x;
edge[i^1].w+=x;
if(edge[i].w)
cur[top] = i;
ans+=x;
if(ans==flow)
return flow;
}
}
if(ans==0)
d[top]=0;
return ans;
}
int dinic()
{
int ans=0;
while(bfs())
{
for(int i=0;i<=3*n+1;i++)
cur[i]=first[i];
ans+=dfs(s,inf);
}
return ans;
}
void floyd()
{
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
if(mp[i][k])
{
for(int j=1;j<=n;j++)
{
if(mp[i][k]&&mp[k][j])
{
mp[i][j]=mp[j][i]=1;
}
}
for(int j=2*n+1;j<=3*n;j++)
{
if(mp[i][k]&&mp[k][j])
{
mp[i][j]=mp[j][i]=1;
}
}
}
}
}
}
int judge(int mid)
{
creat();
for(int i=1;i<=n;i++)
{
add_edge(s,i,mid);
}
for(int i=2*n+1;i<=3*n;i++)
{
add_edge(i,t,mid);
}
for(int i=1;i<=n;i++)
{
add_edge(i,i+n,k);
}
for(int i=1;i<=n;i++)
{
for(int j=2*n+1;j<=3*n;j++)
{
if(mp[i][j])
{
add_edge(i,j,1);
}
else
{
add_edge(i+n,j,1);
}
}
}
int tmp=dinic();
return tmp==mid*n;
}
int main()
{
int T;
scanf("%d",&T);
{
while(T--)
{
scanf("%d %d %d %d",&n,&m,&k,&f);
int u,v,w;
s=0,t=3*n+1;
memset(mp,0,sizeof(mp));
for(int i=1;i<=m;i++)
{
scanf("%d %d",&u,&v);
v+=2*n;
mp[u][v]=mp[v][u]=1;
}
for(int i=1;i<=f;i++)
{
scanf("%d %d",&u,&v);
mp[u][v]=mp[v][u]=1;
}
floyd();
int ans,l=0,r=n,mid;
while(l<=r)
{
mid=(l+r)/2;
if(judge(mid))
{
ans=mid;
l=mid+1;
}
else
{
r=mid-1;
}
}
printf("%d\n",ans);
}
}
return 0;
}